對(duì)于js繼承一直都是半懂半不懂的狀態(tài)工闺,感覺(jué)需要整理一下:
參考自:
JavaScript原型繼承工作原理
JavaScript實(shí)現(xiàn)繼承的幾種方式
JavaScript繼承方式詳解
1. 區(qū)分類繼承和實(shí)例化的差別
非常常用的類繼承是這個(gè)樣子的:
B.prototype = new A()
這時(shí)候特別容易和實(shí)例化給混淆了(反正我混了—):
b = new A()
感覺(jué)不好玩了對(duì)不對(duì),這個(gè)時(shí)候開(kāi)始好奇new到底干了什么事情(理解原理非常重要的撒):
創(chuàng)建類的示例 初始化 返回實(shí)例
用代碼表示如下:
function New (f) {
var n = { '__proto__': f.prototype }; /*第一步*/
return function () {
f.apply(n, arguments); /*第二步*/
return n; /*第三步*/
};
}
還是有點(diǎn)云里霧里攻泼,怎么區(qū)分什么時(shí)候是類繼承竣付,什么時(shí)候是實(shí)例化呢?
吶诡延,首先我先想到一切皆為函數(shù),所以無(wú)論是實(shí)例化還是繼承古胆,本質(zhì)上都是擁有A的屬性(函數(shù)或者值)嘛肆良,所以必須要想清楚js是怎么查找一個(gè)東西的屬性的哇:
當(dāng)查找一個(gè)對(duì)象的屬性時(shí),JavaScript 會(huì)向上遍歷原型鏈逸绎,直到找到給定名稱的屬性為止惹恃。
用代碼表示如下:
function getProperty(obj, prop) {
if (obj.hasOwnProperty(prop)){
return obj[prop]
}else if (obj.__proto__ !== null){
return getProperty(obj.__proto__, prop)
}else{
return undefined
}
}
恩,這下子可以解釋兩者區(qū)別了:
B.prototype = new A()
: B.prototype要找自己屬性的時(shí)候:先看看自己有沒(méi)有 --> 看看自己的proto(也就是A.prototype)有沒(méi)有 --> 一路往上
b = new A()
: b找自己屬性的時(shí)候:先看看自己有沒(méi)有 --> 看看自己的proto(也就是A.prototype)有沒(méi)有 --> 一路往上
n年前收集了一張圖棺牧,仔細(xì)看巫糙,就是我前面整理的內(nèi)容了(不要暈,仔細(xì)看颊乘,此圖博大精深):
對(duì)于原型鏈不理解的其實(shí)可以去看Typescript参淹,對(duì)比Typescript和它生成出來(lái)的js代碼,就容易理解了疲牵。
2. js繼承方式
理解第一節(jié)以后承二,js繼承方式什么的榆鼠,so easy啦~
心中只要記住纲爸,作為子類的我,只要能夠擁有父類prototype里的屬性妆够,就可以算作繼承了(個(gè)人理解识啦,覺(jué)不對(duì)可舉正)
感覺(jué)可以用生孩子的例子貫穿這一節(jié)嘛~
-
原型鏈繼承(其實(shí)就是最開(kāi)始1的那種繼承)
//父類 var Animal = function(){ //可以在構(gòu)造函數(shù)里面直接設(shè)置屬性~ this.name = 'animal'; } //也可以通過(guò)prototype Animal.prototype.say = function(){ console.log('Animal here'); } //子類 var Dog = function(){ } Dog.prototype = new Animal(); //改寫(xiě)父類prototype Dog.prototype.name = 'dog'; //創(chuàng)建實(shí)例 var doge = new Dog(); console.log(doge.name) //'dog'; doge.say() //'Animal here';
最傳統(tǒng)的辦法了,自己生
-
構(gòu)造繼承(借用方法)
//父類還是一樣樣的 var Dog = function(){ Animal.call(this); this.name = 'dog'; } //創(chuàng)建實(shí)例 var doge = new Dog(); console.log(doge.name) //'dog'; doge.say() //error;
咦神妹,哪里不對(duì)颓哮,怎么會(huì)error說(shuō)沒(méi)有這個(gè)方法?!!
仔細(xì)看代碼鸵荠,要理解,Dog只是借用了Animal的構(gòu)造方法冕茅,Animal的say方法是在prototype上的,當(dāng)然找不到了,所以這種方法的問(wèn)題就很明顯啦姨伤,就是并沒(méi)有依靠原型鏈關(guān)系哨坪,就像試管嬰兒嘛,我只是借個(gè)肚子生小孩而已乍楚,基因還是我的(哈哈哈) 也就是說(shuō)如果通過(guò)instanceof檢查doge和Animal的關(guān)系当编,會(huì)發(fā)現(xiàn)返回沒(méi)有關(guān)系的呦。
-
實(shí)例繼承
var Dog = function(){
var dog = new Animal();
dog.name = 'dog';
return dog;
}//創(chuàng)建實(shí)例 var doge = new Dog(); console.log(doge.name) //'dog'; doge.say() //'Animal here'; console.log(doge instanceof Animal) // true console.log(doge instanceof Dog) // false
額徒溪,就好象小明爸爸借隔壁老王過(guò)來(lái)生小明~~ 實(shí)例是父類的實(shí)例忿偷,而不是子類的實(shí)例。
-
拷貝繼承(暴力繼承)
var Dog = function(){
var animal = new Animal();
for(var attr in animal){
this[attr] = animal[attr];
}
this.name = 'dog';
}//創(chuàng)建實(shí)例 var doge = new Dog(); console.log(doge.name) //'dog'; doge.say() //'Animal here'; console.log(doge instanceof Animal) // false console.log(doge instanceof Dog) // true
最野蠻的辦法:把老王家的兒子抓過(guò)來(lái)臊泌,照著他的樣子自己生一個(gè)
-
組合繼承
var Dog = function(){
Animal.call(this, arguments);
this.name = 'dog';
}
Dog.prototype = new Animal();//創(chuàng)建實(shí)例
var doge = new Dog();
console.log(doge.name) //'dog';
doge.say() //'Animal here';
console.log(doge instanceof Dog) // true
console.log(doge instanceof Animal) // true
相當(dāng)于借A肚子生孩子鲤桥,完事拉住孩子和A的手說(shuō):我是你爸,你也來(lái)自A渠概。好處是解決了實(shí)例繼承的問(wèn)題芜壁,壞處嘛,就是叫了兩遍A高氮。
- Object.create(proto[, propertiesObject])
ES5引入慧妄,我看著underscore用的主要也是這個(gè)辦法。
代碼原理解釋:
Object.create = function (parent) {
function F() {}
F.prototype = parent;
return new F();
};
不多解釋了剪芍,至于怎么生塞淹,這個(gè)我真編不出來(lái)了,有點(diǎn)像建個(gè)工廠罪裹,要生娃的基因給我饱普,出來(lái)就是你娃。
其實(shí)說(shuō)多了状共,個(gè)人覺(jué)得重在理解套耕,目標(biāo)是生娃,至于怎么生峡继,就要看清好處壞處了冯袍。
3. 關(guān)于創(chuàng)建對(duì)象模式的一點(diǎn)嗑叨
什么是創(chuàng)建對(duì)象模式?(看到模式就犯頭疼)額碾牌,說(shuō)人話就是實(shí)例化康愤,常見(jiàn)的就是var a = new A()
。
以前還小的時(shí)候看各種模式什么的舶吗,暈頭轉(zhuǎn)向征冷,浪費(fèi)時(shí)間也浪費(fèi)腦力。
所以推薦先實(shí)踐(酒肉穿腸過(guò)誓琼,佛祖心中流)實(shí)踐多了检激,就會(huì)發(fā)現(xiàn)模式不模式肴捉,自己平時(shí)就在用。
//其實(shí)就是好累好累的叔收,下次再補(bǔ)了—
---------此處為撿節(jié)操分割線----------
最近面試發(fā)現(xiàn)自己表達(dá)能力很不行每庆,不知道寫(xiě)出來(lái)的博客會(huì)不會(huì)也整暈別人了== 歡迎舉正~