一、繼承方法概述
二、原型鏈
不瞭解原型鏈的請先看:一文看懂原型鏈
三、繼承方法
- 原型鏈繼承
原型鏈繼承即採用定義子構造函數的prototype指向父類的實例的方法
本質是:父公有+父私有 ---> 子公有
function Parent(){
this.color = ['red','green'];
}
function Child(){
}
Child.prototype = new Parent();//父類的公有和私有屬性被繼承爲子類的公有屬性
var c = new Child();
注意:此時原型鏈並不完整,Child.prototype = Parent實例,但Parent實例的constructor卻指向Parent構造函數,因此c.constructor指向Parent構造函數。
- 藉助構造函數(經典繼承或僞造對象)
藉助構造函數即只在構造函數中使用call(this)函數繼承。
本質:父私有---> 子私有
function Parent(){
this.color = ['red','green'];
}
Parent.prototype.showColor = function(){
console.log(this.color);
}
function Child(){
Parent.call(this); // 父類私有屬性被繼承爲子類私有屬性
}
var c = new Child();
c.color //['red','green']
c.showColor() //undefined
- 組合繼承
組合繼承即同時採用原型鏈和構造函數繼承
本質:父公有+父私有--->子公有, 父私有--->子私有(私有覆蓋公有)
function Parent(){
this.color = ['red','green'];
}
Parent.prototype.showColor = function(){
console.log(this.color)
}
Parent.prototype.name = 'bigP';
function Child(){
Parent.call(this); //第二次調用父類構造函數
}
Child.prototype = new Parent() //第一次調用父類構造函數
var c = new Child()
經過組合繼承,子類的結構爲:子類公有包括:父公有+父私有,子類私有包括:父私有,由於父私有屬性和方法分別存在於子類的公有和私有屬性,根據原型鏈屬性查找的特性,私有屬性優先於公有屬性,因此子類公有屬性中的父私有屬性被覆蓋。
那麼爲什麼會同時存中兩個父私有屬性呢?這要從new 構造函數的實際過程講起。
new Parent()的簡要過程如下:
- 創建一個Object對象:var obj = Object()
- 將新建的對象的[[prototype]]即__proto__指向new 後面的構造函數的prototype: obj.__proto__ = Parent.prototype
- 將構造函數中的this指向新建的對象:Parent.call(obj, 傳入的對象數據) :Parent.call(obj)
- 若函數中有顯式返回其他對象(其他類型忽略),則直接返回其他對象,否則返回新建對象:return obj (即返回實例)
由上述過程可知,在組合繼承中使用了兩次Parent.call(),因此原型對象和構造函數同時繼承了父類的私有變量。
- 原型式繼承
原型式繼承是將原型鏈繼承用函數包裝起來
本質:(還是原型鏈繼承)父公有+父私有--->子公有
//o爲被繼承的父類對象
//區別於原型鏈繼承:父類對象可以用對象字面量定義{},也可以用構造函數new Parent()
function object(o){
function F(){}
F.prototype = o;
return new F();
}
var c = object(o)
由於原型式繼承只是使用了prototype,實際和原型鏈繼承是一樣的效果,只是父類對象不僅可以是構造函數創建的實例,也可用對象字面量定義,只是兩種方法的原型鏈不同。
- 寄生式繼承
寄生式繼承是在原型式繼承的基礎上用函數封裝並添加子類私有屬性的繼承方法,
本質:父公有+父私有--->子公有,新增屬性--->子私有
function createChild(original){
var child = object(original); //使用原型式繼承的函數
child.name = 'newChild'; //添加子類私有屬性和方法
return child;
}
var parent = {
color: ['red','green']
};
var c = createChild(parent);
- 寄生組合式繼承
寄生組合式繼承同樣是在原型式繼承的基礎上用函數封裝,但是通過原型鏈繼承父類的公有屬性,通過構造函數繼承父類的私有屬性。本質:父公有--->子公有,父私有--->子私有。
function inheritePrototype(Child, Parent){
var childProto = object(Parent.prototype);
childProto.constructor = Child
Child.prototype = childProto;
}
function Parent(){
this.color = ['red','green'];
}
Parent.prototype.showColor = function(){
console.log(this.color);
}
function Child(){
Parent.call(this); // 父類的私有屬性被繼承爲子類的私有屬性
}
inheritePtototype(Child,Parent); // 父類的公有屬性被繼承爲子類的公有屬性
在繼承父類公有屬性的函數中,本質是創建了一個空的構造函數F並直接指向Parent.prototype,生成一個只包含父類公有屬性的實例對象,然後將已經繼承了父類私有屬性的構造函數指向該實例對象。