大家好!
先前研究 JavaScript 原型繼承的時候,就覺得非常不單純,例如:
function One() {}
function Two() {}
Two.prototype = Object.create(One.prototype);
Two.prototype.constructor = Two;
new Two(); // Two {}
Two.prototype; // One { ... }
Two.prototype instanceof One; // true
當 Two 繼承 One 後,就能發現 Two.prototype 是由 One 建構出的物件,因此 Two.prototype 很明顯就是 One 的實例。
然而,原生物件型別卻不是如此,例如:
[]; // Array []
Array.prototype; // Array [ ... ]
Array.prototype instanceof Array; // false
這裡 Array.prototype 是由同名的 Array 建構出的物件(父原型應為 Object 不是嗎?),不過 Array.prototype 卻不是 Array 的實例。
再來看一個:
new String(); // String {}
String.prototype; // String { ... }
String.prototype instanceof String; // false
這裡 String.prototype 也是由同名的 String 建構出的物件,但是 String.prototype 卻也不是 String 的實例。
綜上所述,我認為可能的原因是:
原生物件型別的物件和原型所使用的建構式只有名稱相同而已,實際上是位於不同記憶體位置的建構式。
例如:
function One() {}
function Two() {}
Two.prototype = Object.create(Two.prototype);
Two.prototype.constructor = Two;
new Two(); // Two {}
Two.prototype; // Two { ... }
Two.prototype instanceof Two; // false
但是,如果要繼承就更麻煩了。
不知道各位有沒有其他的想法呢?
原生物件型別的物件和原型所使用的建構式只有名稱相同而已,實際上是位於不同記憶體位置的建構式。
以過去學習的經驗,這算是設計上的小巧思
有時像設計第三方套件時
為了要避免"汙染全局"的屬性或方法
會用這種方式去隔開
以避免直接覆蓋掉原屬性方法
感謝回答。
確實如此,可惜無法重現 Array.prototype 為何是 Array 的實例。
ECMA-262 Edition 5.1
§15.4.4 Properties of the Array Prototype Object
§15.5.4 Properties of the String Prototype Object
規範也沒有解釋清楚,只有說 Array.prototype 本身就是 Array 而已,至於作法如何就不得而知了。
也有可能因為是直接指派原型的情況,導致原型鏈被破壞,也因此 Array.prototype 無法成為 Array 的實例?