前言:了解熊師傅的朋友都知道,百度能查的到東西絕對不會提及太多,但是如果能按照思路仔細揣摩相信你一定不會后悔的,接下來開始我的表演。
三分鐘徹悟?哈哈哈。。。
原型鏈自不必說是js前期最晦澀難懂的地方,也是基礎中的基礎,是每一位前端必須有所了解的。
別怕,熊師傅帶你來干 ^ . ^
一.原型鏈繼承
function aaa (name) {
this.name = name;
}
aaa.prototype.getName = function () {
return this.name;
}
function bbb (name) {
}
bbb.prototype = new aaa(‘我是哈哈’);
核心代碼: bbb.prototype = new aaa()
將bbb的原型指向aaa的實例,aaa的屬性和原型方法都將掛載到bbb的原型下面。
缺點:
1.bbb無法給aaa(父類)的構造函數(shù)傳遞參數(shù) (無法繼承構造函數(shù))
2.如果bbb的構造函數(shù)也有name屬性,依然會在原型上繼承aaa的name屬性,造成內(nèi)存浪費
二.借用構造函數(shù)繼承
function aaa () {
this.name = name;
}
aaa.prototype.getName = function () {
return this.name;
}
function bbb (name, age) {
aaa.apply(this, name);
this.age = age;
}
var oBBB = new bbb();
核心代碼: aaa.apply(this, name)
在new bbb() 的 時候調(diào)用aaa,借用aaa的構造函數(shù)。
缺點:
1.無法做到函數(shù)復用(說白了,沒有prototype)
三.組合繼承
function aaa () {
this.name = name;
}
aaa.prototype.getName = function () {
return this.name;
}
function bbb (name, age) {
aaa.apply(this, name);
this.age = age;
}
bbb.prototype = new aaa();
var oBBB = new bbb();
什么是組合繼承?
說白了,就是把前面兩種繼承方式結合起來
核心代碼:
aaa.apply(this, name);
bbb.prototype = new aaa();
思路:bbb通過call借用aaa的構造函數(shù),并將aaa的屬性和原型方法掛載在自己的原型上面。
缺點:
1.依然會造成內(nèi)存浪費,會把aaa的屬性也寫到bbb的原型上面去。
四.原型式繼承
先好好揣摩下這個東西
function object (o) {
function F () {}
F.prototype = o;
return new F();
}
那么這種模式怎么繼承呢?
var aaa = {
name: 'xxx',
age: '18',
}
var aaa1 = object(aaa);
var aaa2 = object(aaa);
很顯然aaa1和aaa2的原型上面都會有name和age屬性。
當然缺點也很明顯了:
1.構造函數(shù)和prototype不分,所有實例的原型引用一致,容易造成重寫,和原型鏈繼承的缺點一樣
五.寄生式繼承
說白了,對原型式繼承做了一次改造。先看看如下東西:
function createAnother (obj) {
var clone = object(obj);
clone.sayHi = function() {
alert('hi');
}
return clone;
}
var aaa = {
name: '111',
age: '2',
};
var aaa1 = createAnother(aaa);
缺點:
1.構造函數(shù)無法復用,也無法接受參數(shù)。(其實有改造空間,把createAnother通過閉包再封裝一層,不過個人不推薦再改造)
六.寄生組合式繼承
堪稱最完美的方式:
// 這個命名牛逼不? in her it ,老鐵,意會 ^.^
function inherit (sub, sup) {
var prototype = object(sup.prototype);
prototype.constructor = sub;
sub.prototype = prototype;
}
function aaa (name) {
this.name = name;
}
aaa.prototype.getName = function () {
alert('111');
}
function bbb (name, age) {
aaa.call(this, name);
this.age = age;
}
inherit(bbb, aaa);
bbb.prototype.xixi = function() {
alert('xixi');
}
到這里基本上解決了所有的問題,perfect。具體的工作原理,前5種繼承方式如果認真研究過一遍了,基本上無需再解釋,若看不懂回過頭來再溫習一遍,熊師傅對于這一塊也是來回研究了十來遍才咯知一二。
但是。
熊師傅對于第六種繼承方式提出一些大家可能會有的疑惑。
1.不是一樣子類繼承父類之后,父類的prototype依然會共享,同一個引用依然會改變父類的原型呀?
2.inherit有什么意義? 和 sub.prototype = sup.prototype有什么區(qū)別?為什么非要通過object方法?
說實話,作者在這里也琢磨了一段時間,算是有一些自己的見解。如有不對,歡迎指正
1.好好想一想我們?yōu)槭裁匆^承?不就是為了復用嗎?如果不是同一個引用,那繼承又有什么意義?(是不是有點恍然大悟的意思^.^)
2.這里通過inherit會重新指正子類sub的構造函數(shù),如果簡單的 sub.prototype = sup.prototype, sub.prototype.constructor = sub 會影響父類sup.