原型鏈繼承
原型鏈作為實現繼承的主要方法,其基本思路是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法, 構造函數,原型和實例之間的關系通過一張圖來解釋一下,需要詳細了解的可以看一下我的另外一篇文章
原型鏈繼承的基本模式如下:
function Parent() {
this.name = "heyushuo";
}
Parent.prototype.sayParentName = function() {
console.log(this.name);
};
function Child() {
this.name = "kebi";
}
//1.此時把Child的原型重寫了,換成了Parent的實例
//2.換句話說,原來存在Parent的實例中的屬性和方法,現在也存在Child.prototype中了
Child.prototype = new Parent();
//3.在繼承了Parent實例中的屬性和方法后基礎上,又添加了屬於自己的一個新方法(這里兩個名字一樣會覆蓋)
Child.prototype.sayChildName = function() {
console.log(this.name);
};
var Person = new Child();
console.log(Person);
//所以現在Person指向Child的原型,Child的原型指向Parent的原型(因為Child的原型對象等於了Parent的實例,這個實例指向Parent的原型)
通過如下圖打印的 Person 看一下他們的關系: 這里特別需要注意的是 Person.constructor 現在指向的是 Parent,因為 Child.prototype 中的 constructor 被重寫了 可以通過如下代碼改變 constructor 的指向
//改變 constructor 的指向
Child.prototype.constructor = Child;
二.如何確定原型和原型的關系呢
1. instanceof (實例對象是否是構造函數函數的實例)
console.log(Person instanceof Child); //true
console.log(Person instanceof Parent); //true
console.log(Person instanceof Object); //true
//由於原型鏈的關系,可以說Person是他們三個中任何一個類型的實例
2.isPrototypeOf(Person) 只要原型鏈中出現過的原型,都可以說是該原型鏈派生的實例的原型(可以理解為是否是實例的原型) Object.prototype.isPrototypeOf(Person) //true Parent.prototype.isPrototypeOf(Person) //true Child.prototype.isPrototypeOf(Person) //true
三.需要注意的問題
再給 Child 添加新的方法的時候,一定要在原型繼承父元素后添加,這樣可以防止自己定義的方法,會和繼承來的方法名字相同,導致 Child 自己定的方法被覆蓋
四.原型鏈繼承的問題
1.實例共享引用類型
雖然原型鏈繼承很強大, 但是存在一個問題, 最主要的問題是包含引用類型值的原型, 因為包含引用類型值的原型屬性會被所有的實例共享, 而在通過原型來實現繼承的時候, 原型實際變成了另外一個函數的實例(這里邊就有可能存在引用類型)
通過一個例子看一下
function Parent() {
this.newArr = ["heyushuo", "kebi"];
}
function Child() {
this.name = "kebi";
}
Child.prototype = new Parent();
var Person1 = new Child();
Person1.newArr.push("kuli");
console.log(Person1.newArr); // ["heyushuo","kebi","kuli"]
var Person2 = new Child();
console.log(Person2.newArr); // ["heyushuo","kebi","kuli"]
2.在創建 Child 的子類的時候,無法像繼承元素傳遞參數