昨天有說明到函式與建構式的原型,及指定建構式函式原型為另一個建構式函式,但其實這會造成覆寫 constructor 的問題。
我們昨天有提到「建構式函式可以透過 .constructor
來存取建立物件的函式以此來作類型檢查。」,但是這個例子卻會導致 trickyMan
的建構式的原型被覆寫,無法去判斷。
function Person(){};
Person.prototype.say = "Hi";
function trickyMan(){};
trickyMan.prototype = new Person();
var Jason = new trickyMan();
trickyMan.constructor === trickyMan;//false
所以如果在 Jason
物件上呼叫 .constructor
,會無法找到直到在 Person
上找到參照 Person
函式的 constructor
。
但是,這事實上是錯誤的,如果我問是哪個函式建立了 Jason
物件,會得到 Person
這可能會產生一些 Bug。
幸好在 JS 中,物件的每個屬性都有一個屬性描述子( property desciptor ),可以夠過它設定以下鍵值:
for-in
迴圈操作中出現先來個簡單的例子:
Jason.age = 29;
age
這個屬性會是 可設定、可列舉並且可寫入的,它的值被設為 29
, get
和 set
函式則會是 undefined
。
如果要對上述設定值做更動的話,可以用 Object.defineProperty
:
var Jason = {};
Jason.say = "R~";
Object.defineProperty(Jason,"age",{
configurable : false,
enumerable : false,
value : 29,
writable : true
});
console.log("age" in Jason);
for(let key in Jason){
console.log(key);
}
好,現在我知道有這東西了,但這跟一開始說的 constructor
有關係嗎?
當然有!我們試著用 trickyMan
擴展( extend )Person
時(也可以說是讓 trickyMan
成為 Person
的子類別),就失去原本保存在 constructor
屬性上的 trickyMan
原型。
我們可以用 Object.defineProperty
在新的 trickyMan.prototype
上定義一個新的 constructor
屬性。
function Person(){};
Person.prototype.say = "Hi";
function trickyMan(){};
trickyMan.prototype = new Person();
Object.defineProperty(trickyMan,"constructor",{
enumerable : false,
value : trickyMan,
writable : true
});
var Jason = new trickyMan();
trickyMan.constructor === trickyMan;//true
那麼,今天就到這邊,一樣如果有錯誤及來源未附上也歡迎留言指正,那麼我們明天見。
參考資料:
忍者 JavaScript 開發技巧探秘
你所不知道的 JS
Javascripter 必須知道的繼承 prototype,[[prototype]]
,proto
該來理解 JavaScript 的原型鍊了
proto VS. prototype in JavaScript