Javascript ES6 Class繼承的原理
1. 前言
ES6新增的Class(類)給我們程式設計帶來了極大方便,有人說這實際上是函式的語法糖,我是贊同的,但詞法作用域和原型鏈是Javascript的核心思想,Class是基於原型鏈實現的,函式也是基於原型鏈實現的,這兩者必然有一些共性,甚至使用 typeof 類識別符號考察類到底是一個什麼東西?控制檯會告訴你這是一個function。然而,Class作為一個新特性,它有函式該有的東西,它也有函式沒有的東西,這是它強大的地方。
2. Class本質上是一個特別的函式
class Polygon { constructor(height, width) { this.name = 'Polygon'; this.height = height; this.width = width; } sayName() { console.log('Hi, I am a ', this.name + '.'); } } class Square extends Polygon { constructor(length) { super(length, length); this.name = 'Square'; } get area() { return this.height * this.width; } set area(value) { this.area = value; } } var mySquare = new Square(4,4);
typeof Polygon //function 控制檯輸入typeof Polygon, 它會告訴你這是一個函式
console.dir(Polygon) //反射檢視Polygon類的屬性
3. Class比函式多一根原型鏈
我們說函式supF是函式subF的父類,是因為subF.__protol__ = sup.prototype,即子函式的原型物件sub.prototype被連結到父函式supF的原型物件supF.prototype。但是兩個父子函式supF和subF本身是獨立的,沒有任何關係,它們是靠原型物件關聯到了一起。Class恰恰把這根連結上了。即子類自己的__protol__指向了父類。簡單理解:extend關鍵字將類和類原型連結到了兩根不同的鏈。
4. super偽引用
我們知道this繫結是動態繫結,super也是動態繫結的嗎?super一定指向物件原型鏈的上級嗎?類有兩根原型鏈,那到底是哪根的上級呢?對於Javascript而言,沒有類也是可以建立物件的,我們可以使用Object.setPrototypeOf(),隨時將一個物件連結到另一個物件,這讓super的指向更加複雜?其實也沒那麼複雜,如前言所講,Javascript的核心思想:詞法作用域鏈和原型鏈,函式被定義的位置和被呼叫的形式,這些能給你答案。
函式是一個獨立的特殊物件,它可以作為物件的方法和普通物件(object)關聯,這種關聯僅僅是一種動態關係,誰也不依賴誰,誰也可以沒有誰。但是函式被建立時關聯的物件很重要,它是函式一出生就看見的物件,函式長大了,會飛了,換了很多環境生活,但是它的故鄉只有一個,稱為[[HomeObject]],它出生時就會用[[HomeObject]]記錄這個故鄉(物件)。
簡單點說: super指向封閉函式定義的物件在原型鏈中的上級。
class P {
foo() {console.log("P.foo");}
}
class C extends P {
//靜態方法的[[HomeObject]]指向Class
//例項方法的[[HomeObject]]指向例項
foo() {
/*
super指向主調函式foo.[[HomeObject]].[[prototype]]
即定義函式的物件的原型鏈上級
*/
super.foo();
}
}
var c1 = new C();
c1.foo();
var D = {
foo: function() {
console.log("D.foo");
}
};
var E = {
foo: C.prototype.foo
};
Object.setPrototypeOf(E,D);
E.foo();