1、當構造函數中包含和原型對象重名的方法和屬性時(構造函數中的會覆蓋原型對象中的方法和屬性)
1 function Person() { 2 this.name="martin"; 3 this.gun=function () { 4 alert("i am a person") 5 } 6 } 7 Person.prototype.gun=function () { 8 alert("biubiu"); 9 } 10 var xiaoGang=new Person(); 11 xiaoGang.gun();//輸出i am a person 12
2、當正常的繼承用法
function Person() { this.name="martin"; } } Person.prototype.gun=function () { alert("biubiu"); } function Student(){ this.name="dick"; } Student.prototype=new Person;//Student原型對象作為Person實例擁有Person構造函數所有屬性方法,並包含指向Person原型對象的指針 } var xiaoMing=new Student(); xiaoMing.gun();//輸出biubiu
原型搜索機制:拿上面的程序舉例,要搜索xiaoMing實例中的gun方法;1、先搜尋xiaoMing實例本身 2、再搜索Student.prototype是否有gun方法 3、最后搜索Person.prototype,發現有所以調用了Person.prototype中的gun方法
針對於整個程序而言gun方法搜索過程:1.xiaoMing實例本身 2、Student構造函數 3、Student.prototype 4、Person構造函數 5、Person.prototype
總結:搜索屬性和方法時從從近到遠搜索,先搜索自身實例,然后搜索離自己最近的子對象,然后父對象(類似於冒泡搜索),同時構造函數中的方法屬性會比其原型對象優先搜索,因為構造函數中的方法屬性會屏蔽(注意和下面覆蓋的區別)原型對象中的方法屬性。
思考:正常的繼承會同時繼承父輩構造函數及其原型對象的方法和屬性,那如果我只要繼承父輩原型對象的方法和屬性怎么辦?
以上面的程序為例:想法:將程序中的Student.prototype=new Person替換成Student.prototype=Person.prototype能否實現
利用程序試驗后得知:改方法可以實現只繼承父輩原型對象的方法屬性,但是因為Person把原型對象地址直接給了Student的原型對象,導致Student和Person原型對象的方法屬性會互相覆蓋,因為他們都指向Person原型對象的地址。
一般編程用到繼承都用組合繼承,方法繼承用原型鏈繼承,屬性繼承用借用構造函數方法繼承,避免了原型鏈繼承和借用構造函數的缺點(回憶兩種方法各自的缺點),並結合了兩者的優點。
function Person(name){ this.name=name; this.color=["red","green","white"]; } Person.prototype.sayname=function () { alert(this.name); } function Student(name,age) { Person.call(this,name); this.age=age; } Student.prototype=new Person; Student.prototype.sayAge=function () { alert(this.age); } var xiaoMing=new Student("xiaoMing",23); xiaoMing.color.push("black"); alert(xiaoMing.color); xiaoMing.sayname(); xiaoMing.sayAge();
1、原型鏈方法繼承的缺點
以上面例子為例,
Student.prototype=new Person;//重點在這一句
這一句就相當於把Student的原型對象變成了Person的一個實例,也相當於創建了Student.prototype.color=["red","green","white"],所以當Student被實例化時,即var xiaoMing=new Student("xiaoMing",23);
Person構造函數中的屬性color會被xiaoMing實例共享,最后導致一改改所有,所以我們屬性繼承不用原型鏈,方法繼承用原型鏈。(詳見Javascript高級編程P167)
2、借用構造函數缺點
因為利用構造函數創建對象,該對象實例化后屬性和方法雖然同名但都是不相等的,因為他們都分屬於不同的實例,調用相同的方法沒必要在不同實例上都創建一遍,所以方法繼承我們一般不用次方法,屬性繼承用借用構造函數方法。
總結:在使用繼承時,對象方法放在原型對象上,屬性放在構造函數里面。