當我們使用原型鏈繼承時,需要謹慎的定義原型上的方法和屬性,因為這可能帶來意外的結果。 一、謹慎的定義原型上的方法。當我們想為一個構造函數的原型上定義一個方法時,一定要在更改原型後再定義,否則新的原型對象上不會有定義的這個方法,導致與我們預期的結果不同。例: 正確操作如下 二、不要使用對象字面量給原型 ...
當我們使用原型鏈繼承時,需要謹慎的定義原型上的方法和屬性,因為這可能帶來意外的結果。
一、謹慎的定義原型上的方法。
當我們想為一個構造函數的原型上定義一個方法時,一定要在更改原型後再定義,否則新的原型對象上不會有定義的這個方法,導致與我們預期的結果不同。例:
1 function superObj(){} 2 superObj.prototype.sayHi=function sayHi(){ 3 console.log('hi'); 4 }; 5 superObj.prototype={ 6 name:'Poly' 7 }; 8 var obj=new superObj(); 9 obj.sayHi();//報錯!! superObj.sayHi is not a function
正確操作如下
1 function superObj(){} 2 superObj.prototype={ 3 name:'Poly' 4 }; 5 superObj.prototype.sayHi=function sayHi(){ 6 console.log('hi'); 7 }; 8 var obj=new superObj(); 9 obj.sayHi();// 'hi'
二、不要使用對象字面量給原型創建屬性/方法。
使用對象字面量,就會新創建一個對象,並把新對象的引用地址賦值給構造函數的prototype。例
1 function superObj(){} 2 superObj.prototype={ 3 sayHi:function sayHi(){ 4 console.log('hi'); 5 } 6 }
正確操作如下:
1 function superObj(){} 2 superObj.prototype.sayHi=function sayHi(){ 3 console.log('hi'); 4 }
三、對象實例與原型存在直接對應關係。
意思就是說當一個對__proto__就會保存原型的引用地址,即使構造函數的prototype發生改變,也不會對之前創建的實例中的__proto__產生影響。例
1 function superObj(){} 2 superObj.prototype.say=function() { 3 console.log('hello'); 4 } 5 var obj=new superObj(); 6 superObj.prototype={ 7 say:function() { 8 console.log('world'); 9 } 10 }; 11 var obj2=new superObj(); 12 obj.say();//'hello' 13 obj2.say();//'world'
四、最好不要給原型上定義值為引用類型的屬性。
如果在原型上定義值為引用類型的屬性,那麼所有實例都會共用該屬性值(引用類型值,指向同一個對象),當其中一個實例修改該引用類型上的值或屬性時,所有實例上的都會發生改變。因此值為引用類型的屬性,最好在構造函數中定義。例
1 function superObj(){} 2 superObj.prototype.ary=[1,2,3]; 3 var obj1=new superObj(); 4 var obj2=new superObj(); 5 obj1.ary[0]=0;//obj1.ary和obj2.ary指向的是同一個數組,當obj1修改此數組時,obj2.ary也會發生改變 6 console.log(obj2.ary[0]);//0
如果不想讓實例共用同一個引用對象,那麼就應該在構造函數中進行定義。例
1 function superObj(){ 2 this.ary=[1,2,3]; 3 } 4 var obj1=new superObj(); 5 var obj2=new superObj(); 6 obj1.ary[0]=0;//obj1.ary和obj2.ary指向的不是同一個數組,所以修改obj1.ary不會影響obj2.ary 7 console.log(obj2.ary[0]);//1