背景
好久都沒有寫原生的js了。突然發(fā)現(xiàn)自己對一些基礎(chǔ)概念有些生疏了,故以紅寶書為基礎(chǔ),總結(jié)下相關(guān)的基礎(chǔ)知識。
原型鏈
js中的繼承主要通過原型鏈來實現(xiàn)。首先來使用原型鏈的基本原理實現(xiàn)一個繼承。
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
}
function SubType() {
this.subproperty = false;
}
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function() {
return this.subproperty;
}
var instance = new SubType();
原型鏈
但是原型鏈實現(xiàn)的繼承也存在一些問題,當(dāng)父類中存在引用類型的值時會被所有子類所共享。同時在創(chuàng)建子類實例時,不能向父類的構(gòu)造函數(shù)中傳遞參數(shù)。
借用構(gòu)造函數(shù)
為了解決引用類型被所有子類所共享的情況,我們可以在子類的構(gòu)造函數(shù)中調(diào)用父類的構(gòu)造函數(shù),從而達(dá)到每個實例都有自己的屬性。同時我們也解決了子類不能向超類穿參的問題。
function SuperType(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
function SubType() {
SuperType.call(this, 'test');
}
當(dāng)然這種方式也有明顯的缺點,我們的方法如果都定義在構(gòu)造函數(shù)中的話就沒法進(jìn)行函數(shù)的復(fù)用了。
組合繼承
其結(jié)合了上述兩種繼承方式的優(yōu)點,使用原型鏈來實現(xiàn)原型的屬性和方法的繼承,使用借用構(gòu)造函數(shù)來實現(xiàn)對實例屬性的繼承。
function SuperType(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
SuperType.prototype.sayName = function() {
alert(this.name);
};
// 繼承屬性
function SubType() {
SuperType.call(this, 'test');
}
//繼承方法
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function() {
alert(this.name);
}
這種方式存在的問題在于會調(diào)用兩次超類的構(gòu)造函數(shù),這使得我們有兩份屬性。
原型式繼承
借助原型基于已有對象創(chuàng)建新對象,同時不必創(chuàng)建自定義的類型
funciton object(o) {
function F() {};
F.prototype = o;
return new F();
}
寄生式繼承
function createAnother(o) {
var clone = object(o);
//增強(qiáng)這個對象
clone.say = function() {};
return clone;
}
寄生組合式繼承
這種方式主要解決了組合繼承會調(diào)用兩次超類的問題。其主要思路是:不必為了指定子類的原型而調(diào)用超類的構(gòu)造函數(shù),我們需要的僅僅只是超類的原型。
function inheritPrototype(subType, superType) {
var prototype = object(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype;
}
這種方式避免了在原型上創(chuàng)造不必要的屬性。
最后附上一個完整的寄生組合式繼承
function extend() {
if (typeof o !== 'function') {
throw "參數(shù)錯誤";
}
o = o || {};
var supr = o, proto,
supro = supr && supr.prototype || {};
function fn() {
supr.apply(this, arguments);
};
proto = (function(fn, o) {
function Foo() {this.constructor = fn};
Foo.prototype = o;
return (fn.prototype = new Foo());
})(fn, supro);
return fn;
}