近來在看阮一峯的網絡日誌,確實寫得好,非常通俗易懂,對我們這些小白受益匪淺!
JavaScript的繼承一直是一大難點,初涉會花費非常多的時間,我也如此。在摸索了許多天之後,逐漸有了一些頭緒。
但是關於constructor屬性重定向這個問題上,我還是存在疑問。
在測試過程中,發現測試的結果與阮一峯老師的結論有些出入,在此記錄。
首先粘上阮一峯老師的這篇博文:http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html
同時爲了方便閱讀,在此將部分內容摘抄:
1、阮一峯老師的"prototype模式"講解
function Animal(){
this.species = "動物";
}
function Cat(name,color){
this.name = name;
this.color = color;
}
要使“貓”繼承“動物”,使用prototype模式的話,就要這樣:Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
var cat1 = new Cat("大毛","黃色");
alert(cat1.species); // 動物
代碼的第一行,我們將Cat的prototype對象指向一個Animal的實例。Cat.prototype = new Animal();
它相當於完全刪除了prototype 對象原先的值,然後賦予一個新值。但是,第二行又是什麼意思呢?Cat.prototype.constructor = Cat;
原來,任何一個prototype對象都有一個constructor屬性,指向它的構造函數。如果沒有"Cat.prototype = new Animal();"這一行,Cat.prototype.constructor是指向Cat的;加了這一行以後,Cat.prototype.constructor指向Animal。alert(Cat.prototype.constructor == Animal); //true
更重要的是,每一個實例也有一個constructor屬性,默認調用prototype對象的constructor屬性。(此處文字加粗,是一會討論的重點)alert(cat1.constructor == Cat.prototype.constructor); // true
因此,在運行"Cat.prototype = new Animal();"這一行之後,cat1.constructor也指向Animal!alert(cat1.constructor == Animal); // true
這顯然會導致繼承鏈的紊亂(cat1明明是用構造函數Cat生成的),因此我們必須手動糾正,將Cat.prototype對象的constructor值改爲Cat。這就是第二行的意思。
這是很重要的一點,編程時務必要遵守。下文都遵循這一點,即如果替換了prototype對象,
o.prototype = {};
那麼,下一步必然是爲新的prototype對象加上constructor屬性,並將這個屬性指回原來的構造函數。o.prototype.constructor = o;
2、關於自己對constructor屬性的理解
function Animal(){
this.species = "動物";
}
var animal = new Animal();
console.info( "constructor" in animal );//true
console.info( animal.hasOwnProperty("constructor") );//false
console.info( animal.__proto__.hasOwnProperty("constructor") );//true
從上面的代碼很明顯的看出,新new出來的實例是沒有constructor屬性的,當訪問實例的constructor屬性時,根據作用域鏈的原則,會到其prototype對象中去找。Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
上面的代碼我們可以如下轉換:var animal = new Animal();
Cat.prototype = animal;
Cat.prototype.constructor = Cat;
此時我們再輸出:console.info("constructor" in animal);//true
console.info( animal.hasOwnProperty("constructor") );//true
console.info( animal.__proto__.hasOwnProperty("constructor") );//true
此時的animal竟然多出了constructor屬性(注意:這裏的animal一直是一個實例)。function Animal(){
this.species = "動物";
}
var animal = new Animal();
console.info(animal);
控制檯輸出數據:然後改寫阮老師代碼:
function Animal(){
this.species = "動物";
}
function Cat(){
this.name="大黃";
}
var animal = new Animal();
Cat.prototype = animal;
Cat.prototype.constructor = Cat;
console.info(animal);