Class
基础
创建 Class
- 大驼峰;
- class 声明不会发生变量提升;
- 块作用域;
// class 声明
class Person {}
// class 表达式
const Animal = class {};
构造函数
- constructor 可选,默认为一个空函数;
- 定义实例属性和实例方法;
const Person = class {
constructor() {
console.log("person ctor");
}
};
实例化
- 创建一个 object;
- object 的 prototype 指向 constructor 的 prototype;
- constructor 的 this 指向 object;
- 执行 constructor 内语句;
- 若 constructor 返回一个 object,则返回该 object,否则返回新创建的对象;
const Person = class {
constructor() {
console.log("0");
}
};
let p1 = new Person(); // 0
new 的强制使用
- 与 function 不同,class 强制使用 new;
- 当 function 不使用 new 时,this 指向 global,class 则会报错;
类方法
分类
实例成员
- 定义在 constructor 中,使用 this 定义;
- 实例的自有属性,不同实例之间相互隔离;
class Person {
constructor() {
this.name = new String("Jack");
this.sayName = () => console.log(this.name);
this.nicknames = ["Jake", "J-Dog"];
}
}
let p1 = new Person(),
p1.sayName(); // Jack
p1.name = p1.nicknames[0];
p1.sayName(); // Jake
原型方法
- 原型方法定义在 class.prototype 中;
- 不同实例之间共享;
class Person {
constructor() {
this.locate = () => console.log("instance");
}
locate() {
console.log("prototype");
}
}
let p = new Person();
p.locate(); // instance
Person.prototype.locate(); // prototype
访问器
- 只定义 get,表明只读;
- 只定义 set,表示只写;
// 写 name 属性时触发 set
// 读 name 属性时触发 get
class Person {
set name(newName) {
this.name_ = newName;
}
get name() {
return this.name_;
}
}
let p = new Person();
p.name = "Jake";
console.log(p.name); // Jake
静态方法
- 定义在 class 对应的 object 上,不需要实例化即可访问;
class Person {
constructor() {
// 实例方法
this.locate = () => console.log("instance", this);
}
// 原型方法
locate() {
console.log("prototype", this);
}
// 静态方法,
static locate() {
console.log("class", this);
}
}
let p = new Person();
p.locate(); // instance, Person {}
Person.prototype.locate(); // prototype, {constructor: ... }
Person.locate(); // class, class Person {}
两种函数形式
两种函数形式
class Test {
// 普通函数
fun() {
console.log(this.color);
}
// 箭头函数
arrow = () => {
console.log(this.color);
};
}
this 的指向
- 普通函数的 this 指向函数被调用时所在词法环境;
- 箭头函数的 this 指向箭头函数定义时所在词法环境;
- 但是箭头函数形式等效于在 constructor 中定义函数,每个实例之间不会共享;
class Test {
color = "red";
fun() {
console.log(this.color);
}
arrow = () => {
console.log(this.color);
};
}
const instance = new Test();
const a = {
color: "green",
};
a.fun = instance.fun;
a.arrow = instance.arrow;
instance.fun(); // red
instance.arrow(); // red
a.fun(); // green
a.arrow(); // red
强制绑定 this
- 在构造器里显式调用 bind 函数绑定 this;
class Person {
constructor(name) {
this.name = name;
this.talk = this.talk.bind(this);
}
talk() {
console.log(`${this.name} says hello`);
}
}
类继承
继承基础
- 使用 extends 关键字;
- 子类继承父类所有的属性和方法;
class Vehicle {
identifyPrototype(id) {
console.log(id, this);
}
}
class Bus extends Vehicle {}
let v = new Vehicle();
let b = new Bus();
b.identifyPrototype("bus"); // bus, Bus {}
v.identifyPrototype("vehicle"); // vehicle, Vehicle {}
super
- 自定义 constructor 必须使用 super;
- 只能用于子类 constructor 和 static method 中;
- 用于调用父类的 constructor 并赋值给子类的 this;
- 当不自定义 constructor 时,自动调用 super;
class Vehicle {
constructor() {
this.hasEngine = true;
}
}
class Bus extends Vehicle {
constructor() {
// 调用 super() 之前, 子类无法使用 this
// 自定义 constructor 必须使用 super(), 或返回一个自定义 object
super();
console.log(this instanceof Vehicle); // true
console.log(this); // Bus { hasEngine: true }
}
}
抽象基类
抽象基类
- 不会被实例化的类。
定义抽象基类
- 使用 new.target 属性,禁止实例化;
class Vehicle {
constructor() {
console.log(new.target);
if (new.target === Vehicle) {
throw new Error("Vehicle cannot be directly instantiated");
}
}
}
// Derived class
class Bus extends Vehicle {}
new Bus(); // class Bus {}
new Vehicle(); // class Vehicle {}
// Error: Vehicle cannot be directly instantiated
定义必须实现的方法
- constructor 中判断 this 是否存在对应方法;
class Vehicle {
constructor() {
if (new.target === Vehicle) {
throw new Error("Vehicle cannot be directly instantiated");
}
if (!this.foo) {
throw new Error("Inheriting class must define foo()");
}
console.log("success!");
}
}
class Bus extends Vehicle {
foo() {}
}
class Van extends Vehicle {}
new Bus(); // success!
new Van(); // Error: Inheriting class must define foo()
多类继承
- js 没有显式支持多类继承,只能手动模拟;
class Vehicle {}
let FooMixin = (Superclass) =>
class extends Superclass {
foo() {
console.log("foo");
}
};
let BarMixin = (Superclass) =>
class extends Superclass {
bar() {
console.log("bar");
}
};
class Bus extends FooMixin(BarMixin(Vehicle)) {}
let b = new Bus();
b.foo(); // foo
b.bar(); // bar
类进阶
class 的本质
- js 中的类就是一个特殊的函数;
const Person = class {};
console.log(Person); // class Person {}
console.log(typeof Person); // function
prototype 属性
- class 具有 prototype 属性;
- 对应原型对象具有 constructor 属性,指向 class 本身。
instanceof 操作符
- 检查实例所属类;
class Person {}
let p = new Person();
console.log(p instanceof Person); // true
类的函数实现
创建类
- 使用构造函数;
function MyClass(name) {
this.name = name;
}
原型方法
- 定义在原型上;
MyClass.prototype.sayHello = function () {
console.log("Hello, " + this.name + "!");
};
静态方法
- 定义在构造函数上;
MyClass.staticMethod = function () {
console.log("This is a static method.");
};
继承
- 使用组合寄生继承;
迭代器和生成器
定义迭代器
class Person {
// 定义在原型上
*createNicknameIterator() {
yield "Jack";
yield "Jake";
yield "J-Dog";
}
// 定义在类上
static *createJobIterator() {
yield "Butcher";
yield "Baker";
yield "Candlestick maker";
}
}
let jobIter = Person.createJobIterator();
console.log(jobIter.next().value); // Butcher
console.log(jobIter.next().value); // Baker
console.log(jobIter.next().value); // Candlestick maker
let p = new Person();
let nicknameIter = p.createNicknameIterator();
console.log(nicknameIter.next().value); // Jack
console.log(nicknameIter.next().value); // Jake
console.log(nicknameIter.next().value); // J-Dog
定义默认 iterator
class Person {
constructor() {
this.nicknames = ["Jack", "Jake", "J-Dog"];
}
*[Symbol.iterator]() {
yield* this.nicknames.entries();
}
}
let p = new Person();
for (let [idx, nickname] of p) {
console.log(nickname);
}
// Jack
// Jake
// J-Dog