Class之間能夠經過extends關鍵字實現繼承,這比ES5的經過修改原型鏈實現繼承,要清晰和方便不少。
瀏覽器
子類必須在constructor方法中調用super方法,不然新建實例時會報錯。bash
這是由於子類沒有本身的this對象,而是繼承父類的this對象,而後對其進行加工。若是不調用super方法,子類就得不到this對象。
ES5的繼承,實質是先創造子類的實例對象this,而後再將父類的方法添加到this上面(Parent.apply(this))。ES6的繼承機制徹底不一樣,實質是先創造父類的實例對象this(因此必須先調用super方法),而後再用子類的構造函數修改this。
app
在子類的構造函數中,只有調用super以後,纔可使用this關鍵字,不然會報錯。這是由於子類實例的構建,是基於對父類實例加工,只有super方法才能返回父類實例。
函數
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); // 調用父類的constructor(x, y)
this.color = color;
}
toString() {
return this.color + ' ' + super.toString(); // 調用父類的toString()
}
}
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class ColorPoint extends Point {
constructor(x, y, color) {
this.color = color; // ReferenceError
super(x, y);
this.color = color; // 正確
}
}
let cp = new ColorPoint(25, 8, 'green');
cp instanceof ColorPoint // true
cp instanceof Point // true複製代碼
類的prototype屬性和proto屬性
ui
大多數瀏覽器的ES5實現之中,每個對象都有proto屬性,指向對應的構造函數的prototype屬性。Class做爲構造函數的語法糖,同時有prototype屬性和proto屬性,所以同時存在兩條繼承鏈。this
1)子類的proto屬性,表示構造函數的繼承,老是指向父類。spa
2)子類prototype屬性的proto屬性,表示方法的繼承,老是指向父類的prototype屬性。prototype
class A {
}
class B extends A {
}
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
複製代碼
Object.getPrototypeOf()
code
Object.getPrototypeOf方法能夠用來從子類上獲取父類。可使用這個方法判斷,一個類是否繼承了另外一個類。
對象
Object.getPrototypeOf(ColorPoint) === Point
// true
複製代碼
Class的取值函數(getter)和存值函數(setter)
與ES5同樣,在Class內部可使用get和set關鍵字,對某個屬性設置存值函數和取值函數,攔截該屬性的存取行爲。
class MyClass {
constructor() {
// ...
}
get prop() {
return 'getter';
}
set prop(value) {
console.log('setter: '+value);
}
}
let inst = new MyClass();
inst.prop = 123;
// setter: 123
inst.prop
// 'getter'
複製代碼
Class不存在變量提高(hoist),這一點與ES5徹底不一樣。
new Foo(); // ReferenceError
class Foo {}
複製代碼
Class當即執行表達式
採用Class表達式,能夠寫出當即執行的Class。
let person = new class {
constructor(name) {
this.name = name; //類的方法內部若是含有this,它默認指向類的實例
}
sayName() {
console.log(this.name);
}
}('張三');
person.sayName(); // "張三"
複製代碼
super這個關鍵字,既能夠看成函數使用,也能夠看成對象使用。在這兩種狀況下,它的用法徹底不一樣。
1) super做爲函數調用時,表明父類的構造函數。ES6 要求,子類的構造函數必須執行一次super函數。
class A {}
class B extends A {
constructor() {
super(); //實例化父類
}
}複製代碼
注意,super雖然表明了父類A的構造函數,可是返回的是子類B的實例,即super內部的this指的是B,所以super()在這裏至關於
2) super做爲對象時,在普通方法中,指向父類的原型對象;在靜態方法中,指向父類。
class A {
p() {
return 2;
}
}
class B extends A {
constructor() {
super();
console.log(super.p()); // 2
//super.p() 至關於 A.prototype.p()
}
}
let b = new B();複製代碼
因爲super指向父類的原型對象,因此定義在父類實例上的方法或屬性,是沒法經過super調用的。
class A {
constructor() {
this.p = 2;
}
}
class B extends A {
get m() {
return super.p;
}
}
let b = new B();
b.m // undefined複製代碼
若是屬性定義在父類的原型對象上,super就能夠取到。
class A {}
A.prototype.x = 2;
class B extends A {
constructor() {
super();
console.log(super.x) // 2
}
}
let b = new B();複製代碼
ES6 規定,經過super調用父類的方法時,super會綁定子類的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複製代碼
上面代碼中,super.print()雖然調用的是A.prototype.print(),可是A.prototype.print()會綁定子類B的this,致使輸出的是2,而不是1。也就是說,實際上執行的是super.print.call(this)。