ES5 constructor对象的语法糖,其中属性都是声明在prototype
class Point {
constructor() {}
toString() {}
toValue() {}
}
// ES5 实现
Point.prototype = {
constructor() {},
toString() {},
toValue() {},
};
类和模块的内部,默认严格模式
类内部声明的方法,均不可枚举
同函数声明,类也可以使用表达式声明
类声明不存在自动提升,保证父类先于子类声明
类中的this默认指向类实例,也会收到严格模式、运行时环境的影响(class 内部是严格模式,所以 this 实际指向的是undefined)
let methodName = 'getArea';
const MyClass = class Me { //类表达式
[methodName]() { //属性表达式
// ...
}
}
class CustomHTMLElement {
constructor(element) {
this.element = element;
}
get html() {
return this.element.innerHTML;
}
set html(value) {
this.element.innerHTML = value;
}}
var descriptor = Object.getOwnPropertyDescriptor(
CustomHTMLElement.prototype, "html");
"get" in descriptor // true
"set" in descriptor // true
静态方法可以与非静态方法重名。
父类的静态方法,可以被子类继承。
老写法的静态属性定义在类的外部。整个类生成以后,再生成静态属性。
声明的位置:
//在constructor()方法里面的this上面
class IncreasingCounter {
constructor() {
this._count = 0;
}
}
// 也可以定义在类的最顶层。
class IncreasingCounter {
_count = 0;
}
不会被子类所继承
symbol唯一性实现
还有提案使用在属性名前面#表示
运算符in可以表示是否属于该实例的私有属性
构造constructor中的特有属性new target确定构造的调用方式(若不是通过new 或 Reflect.construct()调用,则返回undefined),类名.call(arg...)等写法调用构造的方式将报错
constructor()方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。
一个类必须有constructor()方法,如果没有显式定义,一个空的constructor()方法会被默认添加。
类的方法内部如果含有this,它默认指向类的实例。
只有调用super之后,才可以使用this关键字,否则会报错。这是因为子类实例的构建,基于父类实例,只有super方法才能调用父类实例。
防止this指向错误->构造中提前指定this引用
//将该方法的执行环境绑定到指定的this中执行
class Logger {
constructor() {this.printName = this.printName.bind(this); }
}
// 显式声明this的get拦截方法
class Obj {
constructor() {this.getThis = () => this; }
}
const myObj = new Obj();
myObj.getThis() === myObj // true
// Proxy 获取方法时候,自动绑定到this,实例篇幅较长,见文档
extends ES6的继承方式,Es5通过修改原型链实现继承
ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。
super这个关键字,既可以当作函数使用,也可以当作对象使用。
super的时候,如果能清晰地表明super的数据类型(对象或是函数),就不会报错。
class A {
constructor() {
console.log(new.target.name);
}
}
class B extends A {
constructor() {
super();
}
}
new A() // A
new B() // B
super虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B的实例,因此super()在这里相当于A.prototype.constructor.call(this)。
ES6 规定,在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例。也就是说,实际上执行的是
super.print.call(this)。
class A {
constructor() {
this.x = 1;
}
print() {
console.log(this.x);
}
}
class B extends A {
constructor() {
super();
this.x = 2;
}
m() {
super.print();
}
}
let b = new B();
b.m() // 2
Class 作为构造函数的语法糖,同时有prototype属性和__proto__属性,因此同时存在两条继承链。
子类的原型与父类的关系:
Object.setPrototypeOf(B.prototype, A.prototype);
// 等同于
B.prototype.__proto__ = A.prototype;
Object.setPrototypeOf(B, A);
// 等同于
B.__proto__ = A;
这两条继承链,可以这样理解:作为一个对象,子类(B)的原型(__proto__属性)是父类(A);作为一个构造函数,子类(B)的原型对象(prototype属性)是父类的原型对象(prototype属性)的实例。
Mixin 指的是多个对象合成一个新的对象,新对象具有各个组成成员的接口。