類的概念
雖然 JavaScript 中有類的概念励七,但是可能大多數(shù) JavaScript 程序員并不是非常熟悉類妈倔,這里對類相關(guān)的概念做一個簡單的介紹楼熄。
- 類(Class):定義了一件事物的抽象特點(diǎn)疚察,包含它的屬性和方法
- 對象(Object):類的實(shí)例运褪,通過 new 生成
- 面向?qū)ο螅∣OP)的三大特性:封裝、繼承狰右、多態(tài)
- 封裝(Encapsulation):將對數(shù)據(jù)的操作細(xì)節(jié)隱藏起來杰捂,只暴露對外的接口。外界調(diào)用端不需要(也不可能)知道細(xì)節(jié)棋蚌,就能通過對外提供的接口來訪問該對象嫁佳,同時也保證了外界無法任意更改對象內(nèi)部的數(shù)據(jù)
- 繼承(Inheritance):子類繼承父類,子類除了擁有父類的所有特性外谷暮,還有一些更具體的特性
- 多態(tài)(Polymorphism):由繼承而產(chǎn)生了相關(guān)的不同的類蒿往,對同一個方法可以有不同的響應(yīng)。比如 Cat 和 Dog 都繼承自 Animal湿弦,但是分別實(shí)現(xiàn)了自己的 eat 方法瓤漏。此時針對某一個實(shí)例,我們無需了解它是 Cat 還是 Dog,就可以直接調(diào)用 eat 方法蔬充,程序會自動判斷出來應(yīng)該如何執(zhí)行 eat
- 存取器(getter & setter):用以改變屬性的讀取和賦值行為
- 修飾符(Modifiers):修飾符是一些關(guān)鍵字俯在,用于限定成員或類型的性質(zhì)。比如 public 表示公有屬性或方法
- 抽象類(Abstract Class):抽象類是供其他類繼承的基類娃惯,抽象類不允許被實(shí)例化。抽象類中的抽象方法必須在子類中被實(shí)現(xiàn)
- 接口(Interfaces):不同類之間公有的屬性或方法肥败,可以抽象成一個接口趾浅。接口可以被類實(shí)現(xiàn)(implements)。一個類只能繼承自另一個類馒稍,但是可以實(shí)現(xiàn)多個接口
ES5 類的寫法
function Person(name) {
this.name = name;
this.age = 0;
}
Person.prototype.addAge = function () {
this.age++;
console.log(this,this.name, this.age);
};
let person1 = new Person("Nick");
person1.addAge(); // Person { name: 'Nick', age: 1 } 'Nick' 1
let person2 = new Person("Ming");
person2.addAge(); // Person { name: 'Ming', age: 1 } 'Ming' 1
ES6 類的寫法
class Person {
static single = null;
constructor(name) {
this.name = name;
this.age = 0;
}
addAge() {
this.age++;
console.log(this, this.name, this.age);
}
static getInstance() {
if (this.single === null) {
this.single = new Person("Hi");
}
return this.single;
}
}
let person1 = new Person("Nick");
person1.addAge(); // Person { name: 'Nick', age: 1 } 'Nick' 1
let person2 = new Person("Ming");
person2.addAge(); // Person { name: 'Ming', age: 1 } 'Ming' 1
Person.getInstance().addAge(); // Person { name: 'Hi', age: 1 } 'Hi' 1
ES5 類的繼承
/**
* js 類的實(shí)現(xiàn)
* @type {Base}
*/
var Base = (function () {
function Base(name) {
this.name = name;
}
Base.prototype.getName = function () {
console.log(this.name);
}
return Base;
})();
let base = new Base("Nick");
base.getName(); // Nick
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({__proto__: []} instanceof Array && function (d, b) {
d.__proto__ = b;
}) ||
function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
};
return function (d, b) {
extendStatics(d, b);
function __() {
this.constructor = d;
}
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
/**
* js 繼承
* @type {function(*=): (*|Device)}
*/
var Device = (function (_super) {
__extends(Device, _super);
function Device(name) {
return _super.call(this, name) || this;
}
return Device;
})(Base);
let device = new Device("Jack");
device.getName(); //Jack
ES6 類的繼承
使用 extends 關(guān)鍵字實(shí)現(xiàn)繼承皿哨,子類中使用 super 關(guān)鍵字來調(diào)用父類的構(gòu)造函數(shù)和方法。
class Base {
constructor(name) {
this.name = name;
}
getName() {
console.log(this.name);
}
}
let base = new Base('Nick');
base.getName(); // Nick
class Device extends Base {
constructor(name) {
super(name);
}
}
let device = new Device('Jack');
device.getName(); //Jack
ES5 多態(tài)
function study(person) {
person.study();
};
function Teacher(name) {
this.name = name
};
Teacher.prototype.study = function () {
console.log(` Teacher ${this.name} do something!`);
};
function Student(name) {
this.name = name;
}
Student.prototype.study = function () {
console.log(` Student ${this.name} do something!`);
};
let teacher = new Teacher("Nick");
study(teacher);
let student = new Student("Jack");
study(student);
ES6 多態(tài)
abstract class PersonDao {
abstract study(): string;
}
class Student extends PersonDao {
name: string;
constructor(name) {
super();
this.name = name;
}
study(): string {
return `Student ${this.name} do something!`;
}
}
class Teacher extends PersonDao {
name: string;
constructor(name) {
super();
this.name = name;
}
study(): string {
return `Teacher ${this.name} do something!`;
}
}
let teacher: PersonDao = new Teacher("Nick");
console.log(teacher.study());
let student: PersonDao = new Student("Jack");
console.log(student.study());
存取器
使用 getter 和 setter 可以改變屬性的賦值和讀取行為:
class Animal {
constructor(name) {
this.name = name;
}
get name() {
return 'Jack';
}
set name(value) {
console.log('setter: ' + value);
}
}
let a = new Animal('Kitty'); // setter: Kitty
a.name = 'Tom'; // setter: Tom
console.log(a.name); // Jack
ES7 靜態(tài)屬性和方法
class Animal {
static name='Hi';
static isAnimal(a) {
return a instanceof Animal;
}
}
let a = new Animal('Jack');
console.log(Animal.name); // Hi
Animal.isAnimal(a); // true
a.isAnimal(a); // TypeError: a.isAnimal is not a function