關鍵事約Array
是一個真正的數組對象是Array Exotic Object。一個奇特的對象是一個具有無法使用標準JS語言特性實現的行爲的對象,儘管在ES6 Proxy
中允許用戶代碼創建類似異國情調的對象的能力更多。
當子類構造函數返回像Array
這樣的奇怪對象時,子類化方法需要以這樣的方式完成,即創建的對象實際上是一個外來對象。當你這樣做
function ArraySubclass(){}
ArraySubclass.prototype = Object.create(Array.prototype);
然後
(new ArraySubclass()) instanceof Array
因爲原型相匹配,但new ArraySubclass
返回的對象僅僅是一個正常的對象恰好在其原型鏈Array.prototype
。但你會注意到,
Array.isArray(new ArraySubclass()); // false
因爲對象不是一個真正的奇特。在這種情況下
new ArraySubclass()
所以在ES5你如何延長Array
等同於做
var obj = Object.create(ArraySubclass.prototype);
ArraySubclass.call(obj);
?您需要創建一個奇特的對象,但是您還需要確保異國情調的對象在其原型鏈中有對象ArraySubclass.prototype
。這就是ES5遇到的問題,因爲在ES5中,沒有辦法改變現有對象的原型。隨着__proto__
擴展,很多搜索引擎添加你可以得到下面類似的代碼
var obj = new Array();
obj.__proto__ = ArraySubclass.prototype;
ArraySubclass.call(obj);
說你想概括上面的圖案,你會怎麼做正確的數組子類的行爲嗎?
function makeSubclass(baseConstructor, childConstructor){
var obj = new baseConstructor();
obj.__proto__ = childConstructor.prototype;
return obj;
}
function ArraySubclass(){
var arr = makeSubclass(Array, ArraySubclass);
// do initialization stuff and use 'arr' like 'this'
return arr;
}
ArraySubclass.prototype = Object.create(Array.prototype);
這樣在ES5 + __proto__
中工作,但是情況會變得更復雜嗎?如果你想子類ArraySubclass
怎麼辦?你必須能夠改變第二個參數makeSubclass
。但我們如何做到這一點?這裏的實際目標是什麼?當你這樣做
new ArraySubclass()
它傳遞給我們關心作爲第二個參數new
的值,它是一個應該得到傳承下去該構造函數的原型。 ES5沒有很好的途徑來完成這個任務。
這是ES6課程的好處。
class ArraySubclass extends Array {
constructor(){
super();
}
}
關鍵的一點是,當super()
運行時,它知道ArraySubclass
是子類。當super()
調用new Array
時,它還傳遞了一個額外的隱藏參數,它說:「嘿,當你創建這個數組時,將它的原型設置爲ArraySubclass.prototype
。如果有很多級別的繼承,它將傳遞最小的原型,返回的外來物體是一個真正的異國情調,同時也確保它具有正確的原型
這不僅意味着事物構造正確,而且意味着引擎可以創建具有正確原型值的對象。對象的__proto__
創建後的值是一個衆所周知的去優化點,因爲引擎處理和跟蹤對象的方式不同。
ES5不支持從Array繼承此方式嘿沒有投入ES5)。當你嘗試時,你會失去'.length'的特殊功能,所以它不能正常工作。 ES6有能力子類化Array。 – jfriend00
*「想知道爲什麼這解決了問題」*因爲超級構造函數('Array')創建了具有所有特殊內部行爲的對象,而不是子構造函數。 –