欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

小白談?wù)剬?duì)JS原型鏈的理解

 更新時(shí)間:2024年07月16日 17:24:54   作者:茄果  
這篇文章主要介紹了小白談?wù)剬?duì)JS原型鏈的理解的相關(guān)資料,需要的朋友可以參考下

原型鏈理解起來(lái)有點(diǎn)繞了,網(wǎng)上資料也是很多,每次晚上睡不著的時(shí)候總喜歡在網(wǎng)上找點(diǎn)原型鏈和閉包的文章看,效果極好。

function Person (name) { this.name = name; }
function Mother () { }
Mother.prototype = { //Mother的原型
age: 18,
home: ['Beijing', 'Shanghai']
};
Person.prototype = new Mother(); //Person的原型為Mother
//用chrome調(diào)試工具查看,提供了__proto__接口查看原型
var p1 = new Person('Jack'); //p1:'Jack'; __proto__:18,['Beijing','Shanghai']
var p2 = new Person('Mark'); //p2:'Mark'; __proto__:18,['Beijing','Shanghai']
p1.age = 20; 
/* 實(shí)例不能改變?cè)偷幕局祵傩?,正如你洗剪吹染黃毛跟你媽無(wú)關(guān)
* 在p1實(shí)例下增加一個(gè)age屬性的普通操作,與原型無(wú)關(guān)。跟var o{}; o.age=20一樣。
* p1:下面多了個(gè)屬性age,而__proto__跟 Mother.prototype一樣,age=18。
* p2:只有屬性name,__proto__跟 Mother.prototype一樣
*/
p1.home[0] = 'Shenzhen'; 
/* 原型中引用類(lèi)型屬性的共享,正如你燒了你家,就是燒了你全家的家
* 這個(gè)先過(guò),下文再仔細(xì)嘮叨一下可好?
* p1:'Jack',20; __proto__:18,['Shenzhen','Shanghai']
* p2:'Mark'; __proto__:18,['Shenzhen','Shanghai']
*/
p1.home = ['Hangzhou', 'Guangzhou']; 
/* 其實(shí)跟p1.age=20一樣的操作。換成這個(gè)理解: var o{}; o.house=['big','house']
* p1:'Jack',20,['Hangzhou','Guangzhou']; __proto__:18,['Shenzhen','Shanghai']
* p2:'Mark'; __proto__:18,['Shenzhen','Shanghai']
*/
delete p1.age; 
/* 刪除自定義的屬性之后,原本被覆蓋的原型值就重見(jiàn)天日了。這里就是向上搜索機(jī)制,所以才有下面的動(dòng)態(tài)性
* p1:'Jack',['Hangzhou','Guangzhou']; __proto__:18,['Shenzhen','Shanghai']
* p2:'Mark'; __proto__:18,['Shenzhen','Shanghai']
*/
Person.prototype.lastName = 'Jin'; 
/* 改寫(xiě)原型,動(dòng)態(tài)反應(yīng)到實(shí)例中。正如你媽變新潮了,鄰居提起你都說(shuō)是潮婦的兒子
* 注意,這里我們改寫(xiě)的是Person的原型,就是往Mother里加一個(gè)lastName屬性,等同于Mother.lastName='Jin'
* 這里并不是改Mother.prototype,改動(dòng)不同的層次,效果往往會(huì)有很大的差異。
* p1:'Jack',['Hangzhou','Guangzhou']; __proto__:'jin';__proto__:18,['Shenzhen','Shanghai']
* p2:'Mark'; __proto__:'jin';__proto__:18,['Shenzhen','Shanghai']
*/
Person.prototype = { 
age: 28, 
address: { country: 'USA', city: 'Washington' }
};
var p3 = new Person('Obama'); 
/* 重寫(xiě)原型!這個(gè)時(shí)候Person的原型已經(jīng)完全變成一個(gè)新的對(duì)象了,也就是說(shuō)Person換了個(gè)娘。
* 換成這樣理解:var a=10; b=a; a=20; c=a。所以b不變,變得是c,所以p3變化了,與Mother無(wú)關(guān)。
* p1:'Jack',['Hangzhou','Guangzhou']; __proto__:'jin';__proto__:18,['Shenzhen','Shanghai']
* p2:'Mark'; __proto__:'jin';__proto__:18,['Shenzhen','Shanghai']
* p3:'Obama';__proto__: 28 {country: 'USA', city: 'Washington'}
*/
Mother.prototype.no = 9527;
/* 改寫(xiě)原型的原型,動(dòng)態(tài)反應(yīng)到實(shí)例中。正如你媽他媽變新潮了,鄰居提起你都說(shuō)你丫外婆真潮
* 注意,這里我們改寫(xiě)的是Mother.prototype,p1p2會(huì)變,但上面p3跟Mother已經(jīng)了無(wú)瓜葛了,不影響他。
* p1:'Jack',['Hangzhou','Guangzhou']; __proto__:'jin';__proto__:18,['Shenzhen','Shanghai'],9527
* p2:'Mark'; __proto__:'jin';__proto__:18,['Shenzhen','Shanghai'],9527
* p3:'Obama';__proto__: 28 {country: 'USA', city: 'Washington'}
*/
Mother.prototype = { 
car: 2, 
hobby: ['run','walk']
};
var p4 = new Person('Tony');
/* 重寫(xiě)原型的原型!這個(gè)時(shí)候Mother的原型已經(jīng)完全變成一個(gè)新的對(duì)象了!
* 由于上面Person與Mother已經(jīng)斷開(kāi)聯(lián)系了,這時(shí)候Mother怎么變已經(jīng)不影響Person了。
* p4:'Tony';__proto__: 28 {country: 'USA', city: 'Washington'}
*/
Person.prototype = new Mother(); //再次綁定
var p5 = new Person('Luffy');
// 這個(gè)時(shí)候如果需要應(yīng)用這些改動(dòng)的話(huà),那就要重新將Person的原型綁到mother上了
// p5:'Luffy';__proto__: 2, ['run','walk']
p1.__proto__.__proto__.__proto__.__proto__ //null,你說(shuō)原型鏈的終點(diǎn)不是null?
Mother.__proto__.__proto__.__proto__ //null,你說(shuō)原型鏈的終點(diǎn)不是null? 

看完基本能理解了吧?

現(xiàn)在再來(lái)說(shuō)說(shuō) p1.age = 20、p1.home = ['Hangzhou', 'Guangzhou'] 和 p1.home[0] = 'Shenzhen' 的區(qū)別。 p1.home[0] = 'Shenzhen'; 總結(jié)一下是 p1.object.method,p1.object.property 這樣的形式。

p1.age = 20; p1.home = ['Hangzhou', 'Guangzhou'];這兩句還是比較好理解的,先忘掉原型吧,想想我們是怎么為一個(gè)普通對(duì)象增加屬性的:

var obj = new Object();
obj.name='xxx'; 
obj.num = [100, 200]; 

這樣是不是就理解了呢?一樣一樣的呀。

那為什么 p1.home[0] = 'Shenzhen' 不會(huì)在 p1 下創(chuàng)建一個(gè) home 數(shù)組屬性,然后將其首位設(shè)為 'Shenzhen'呢? 我們還是先忘了這個(gè),想想上面的obj對(duì)象,如果寫(xiě)成這樣: var obj.name = 'xxx', obj.num = [100, 200],能得到你要的結(jié)果嗎? 顯然,除了報(bào)錯(cuò)你什么都得不到。因?yàn)閛bj還未定義,又怎么能往里面加入東西呢?同理,p1.home[0]中的 home 在 p1 下并未被定義,所以也不能直接一步定義 home[0] 了。如果要在p1下創(chuàng)建一個(gè) home 數(shù)組,當(dāng)然是這么寫(xiě)了:

p1.home = []; 
p1.home[0] = 'Shenzhen'; 

這不就是我們最常用的辦法嗎?

而之所以 p1.home[0] = 'Shenzhen' 不直接報(bào)錯(cuò),是因?yàn)樵谠玩溨杏幸粋€(gè)搜索機(jī)制。當(dāng)我們輸入 p1.object 的時(shí)候,原型鏈的搜索機(jī)制是先在實(shí)例中搜索相應(yīng)的值,找不到就在原型中找,還找不到就再往上一級(jí)原型中搜索……一直到了原型鏈的終點(diǎn),就是到null還沒(méi)找到的話(huà),就返回一個(gè) undefined。當(dāng)我們輸入 p1.home[0] 的時(shí)候,也是同樣的搜索機(jī)制,先搜索 p1 看有沒(méi)有名為 home 的屬性和方法,然后逐級(jí)向上查找。最后我們?cè)贛other的原型里面找到了,所以修改他就相當(dāng)于修改了 Mother 的原型啊。

一句話(huà)概括:p1.home[0] = 'Shenzhen' 等同于 Mother.prototype.home[0] = 'Shenzhen'。

由上面的分析可以知道,原型鏈繼承的主要問(wèn)題在于屬性的共享,很多時(shí)候我們只想共享方法而并不想要共享屬性,理想中每個(gè)實(shí)例應(yīng)該有獨(dú)立的屬性。因此,原型繼承就有了下面的兩種改良方式:

1)組合繼承

function Mother (age) {
this.age = age;
this.hobby = ['running','football']
}
Mother.prototype.showAge = function () {
console.log(this.age); 
};
function Person (name, age) { 
Mother.call(this, age);  //第二次執(zhí)行
this.name = name; 
}
Person.prototype = new Mother();  //第一次執(zhí)行
Person.prototype.constructor = Person;
Person.prototype.showName = function () {
console.log(this.name);
}
var p1 = new Person('Jack', 20); 
p1.hobby.push('basketball'); //p1:'Jack'; __proto__:20,['running','football']
var p2 = new Person('Mark', 18); //p2:'Mark'; __proto__:18,['running','football'] 

結(jié)果是醬紫的:

 

這里第一次執(zhí)行的時(shí)候,得到 Person.prototype.age = undefined, Person.prototype.hobby = ['running','football'],第二次執(zhí)行也就是 var p1 = new Person('Jack', 20) 的時(shí)候,得到 p1.age =20, p1.hobby = ['running','football'],push后就變成了 p1.hobby = ['running','football', 'basketball']。其實(shí)分辨好 this 的變化,理解起來(lái)也是比較簡(jiǎn)單的,把 this 簡(jiǎn)單替換一下就能得到這個(gè)結(jié)果了。 如果感覺(jué)理解起來(lái)比較繞的話(huà),試著把腦子里面的概念扔掉吧,把自己當(dāng)瀏覽器從上到下執(zhí)行一遍代碼,結(jié)果是不是就出來(lái)了呢?

通過(guò)第二次執(zhí)行原型的構(gòu)造函數(shù) Mother(),我們?cè)趯?duì)象實(shí)例中復(fù)制了一份原型的屬性,這樣就做到了與原型屬性的分離獨(dú)立。細(xì)心的你會(huì)發(fā)現(xiàn),我們第一次調(diào)用 Mother(),好像什么用都沒(méi)有呢,能不調(diào)用他嗎?可以,就有了下面的寄生組合式繼承。

2)寄生組合式繼承

function object(o){
function F(){}
F.prototype = o;
return new F();
}
function inheritPrototype(Person, Mother){
var prototype = object(Mother.prototype); 
prototype.constructor = Person; 
Person.prototype = prototype; 
}
function Mother (age) {
this.age = age;
this.hobby = ['running','football']
}
Mother.prototype.showAge = function () {
console.log(this.age); 
};
function Person (name, age) { 
Mother.call(this, age);
this.name = name; 
}
inheritPrototype(Person, Mother);
Person.prototype.showName = function () {
console.log(this.name);
}
var p1 = new Person('Jack', 20); 
p1.hobby.push('basketball');//p1:'Jack'; __proto__:20,['running','football']
var p2 = new Person('Mark', 18); //p2:'Mark'; __proto__:18,['running','football'] 

結(jié)果是醬紫的:

 

原型中不再有 age 和 hobby 屬性了,只有兩個(gè)方法,正是我們想要的結(jié)果!

關(guān)鍵點(diǎn)在于 object(o) 里面,這里借用了一個(gè)臨時(shí)對(duì)象來(lái)巧妙避免了調(diào)用new Mother(),然后將原型為 o 的新對(duì)象實(shí)例返回,從而完成了原型鏈的設(shè)置。很繞,對(duì)吧,那是因?yàn)槲覀儾荒苤苯釉O(shè)置 Person.prototype = Mother.prototype 啊。

小結(jié)

-------------------------------------------------------------------------------

說(shuō)了這么多,其實(shí)核心只有一個(gè):屬性共享和獨(dú)立的控制,當(dāng)你的對(duì)象實(shí)例需要獨(dú)立的屬性,所有做法的本質(zhì)都是在對(duì)象實(shí)例里面創(chuàng)建屬性。若不考慮太多,你大可以在Person里面直接定義你所需要獨(dú)立的屬性來(lái)覆蓋掉原型的屬性??傊褂迷屠^承的時(shí)候,要對(duì)于原型中的屬性要特別注意,因?yàn)樗麄兌际菭恳话l(fā)而動(dòng)全身的存在。

下面簡(jiǎn)單羅列下js中創(chuàng)建對(duì)象的各種方法,現(xiàn)在最常用的方法是組合模式,熟悉的同學(xué)可以跳過(guò)到文章末尾點(diǎn)贊了。

1)原始模式

//1.原始模式,對(duì)象字面量方式
var person = { 
name: 'Jack',
age: 18,
sayName: function () { alert(this.name); }
};
//1.原始模式,Object構(gòu)造函數(shù)方式
var person = new Object();
person.name = 'Jack';
person.age = 18;
person.sayName = function () {
alert(this.name);
}; 

顯然,當(dāng)我們要?jiǎng)?chuàng)建批量的person1、person2……時(shí),每次都要敲很多代碼,資深copypaster都吃不消!然后就有了批量生產(chǎn)的工廠(chǎng)模式。

2)工廠(chǎng)模式

//2.工廠(chǎng)模式,定義一個(gè)函數(shù)創(chuàng)建對(duì)象
function creatPerson (name, age) {
var temp = new Object(); 
person.name = name;
person.age = age;
person.sayName = function () {
alert(this.name);
};
return temp; 
}

工廠(chǎng)模式就是批量化生產(chǎn)。指定姓名年齡就可以造一堆小寶寶啦,解放雙手。但是由于是工廠(chǎng)暗箱操作的,所以你不能識(shí)別這個(gè)對(duì)象到底是什么類(lèi)型、是人還是狗傻傻分不清(instanceof 測(cè)試為 Object),另外每次造人時(shí)都要?jiǎng)?chuàng)建一個(gè)獨(dú)立的temp對(duì)象,代碼臃腫,雅蠛蝶啊。

3)構(gòu)造函數(shù)

//3.構(gòu)造函數(shù)模式,為對(duì)象定義一個(gè)構(gòu)造函數(shù)
function Person (name, age) {
this.name = name;
this.age = age;
this.sayName = function () {
alert(this.name);
}; 
}
var p1 = new Person('Jack', 18); //創(chuàng)建一個(gè)p1對(duì)象
Person('Jack', 18); //屬性方法都給window對(duì)象,window.name='Jack',window.sayName()會(huì)輸出Jack 

構(gòu)造函數(shù)與C++、Java中類(lèi)的構(gòu)造函數(shù)類(lèi)似,易于理解,另外Person可以作為類(lèi)型識(shí)別(instanceof 測(cè)試為 Person 、Object)。但是所有實(shí)例依然是獨(dú)立的,不同實(shí)例的方法其實(shí)是不同的函數(shù)。這里把函數(shù)兩個(gè)字忘了吧,把sayName當(dāng)做一個(gè)對(duì)象就好理解了,就是說(shuō)張三的 sayName 和李四的 sayName是不同的存在,但顯然我們期望的是共用一個(gè) sayName 以節(jié)省內(nèi)存。

4)原型模式

//4.原型模式,直接定義prototype屬性
function Person () {}
Person.prototype.name = 'Jack';
Person.prototype.age = 18;
Person.prototype.sayName = function () { alert(this.name); };
//4.原型模式,字面量定義方式
function Person () {}
Person.prototype = {
name: 'Jack',
age: 18,
sayName: function () { alert(this.name); }
};
var p1 = new Person(); //name='Jack'
var p2 = new Person(); //name='Jack' 

這里需要注意的是原型屬性和方法的共享,即所有實(shí)例中都只是引用原型中的屬性方法,任何一個(gè)地方產(chǎn)生的改動(dòng)會(huì)引起其他實(shí)例的變化。

5)混合模式(構(gòu)造+原型)

//5. 原型構(gòu)造組合模式,
function Person (name, age) {
this.name = name;
this.age = age;
}
Person.prototype = {
hobby: ['running','football'];
sayName: function () { alert(this.name); },
sayAge: function () { alert(this.age); }
};
var p1 = new Person('Jack', 20); 
//p1:'Jack',20; __proto__: ['running','football'],sayName,sayAge
var p2 = new Person('Mark', 18); 
//p1:'Mark',18;__proto__: ['running','football'],sayName,sayAge 

做法是將需要獨(dú)立的屬性方法放入構(gòu)造函數(shù)中,而可以共享的部分則放入原型中,這樣做可以最大限度節(jié)省內(nèi)存而又保留對(duì)象實(shí)例的獨(dú)立性。

相關(guān)文章

  • 添加JavaScript重載函數(shù)的輔助方法2

    添加JavaScript重載函數(shù)的輔助方法2

    話(huà)說(shuō),人就是要被關(guān)注才有動(dòng)力啊于是修改了下上次寫(xiě)的《添加JavaScript重載函數(shù)的輔助方法》在添加方法的時(shí)候增加了一個(gè)參數(shù) 用于限制參數(shù)的類(lèi)型。
    2010-07-07
  • Bootstrap每天必學(xué)之柵格系統(tǒng)(布局)

    Bootstrap每天必學(xué)之柵格系統(tǒng)(布局)

    Bootstrap每天必學(xué)之柵格系統(tǒng),小編對(duì)Bootstrap柵格系統(tǒng)(布局)也很陌生,特分享整理這篇文章,感興趣的小伙伴們可以參考一下
    2015-11-11
  • JavaScript MutationObserver實(shí)例講解

    JavaScript MutationObserver實(shí)例講解

    MutationObserver用來(lái)監(jiān)視DOM變動(dòng)。DOM的任何變動(dòng),比如節(jié)點(diǎn)增減、屬性的變動(dòng)、文本內(nèi)容的變動(dòng)都會(huì)觸發(fā)MutationObserver事件,它與事件有一個(gè)本質(zhì)不同:事件是同步觸發(fā),MutationObserver則是異步觸發(fā),DOM的變動(dòng)并不會(huì)馬上觸發(fā),而是要等到當(dāng)前所有DOM操作都結(jié)束才觸發(fā)
    2022-12-12
  • ES6新特性之Symbol類(lèi)型用法分析

    ES6新特性之Symbol類(lèi)型用法分析

    這篇文章主要介紹了ES6新特性之Symbol類(lèi)型用法,結(jié)合形式分析了Symbol類(lèi)型的功能、使用方法及相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2017-03-03
  • JS中的構(gòu)造函數(shù)詳細(xì)解析

    JS中的構(gòu)造函數(shù)詳細(xì)解析

    本篇文章主要是對(duì)JS中的構(gòu)造函數(shù)進(jìn)行了詳細(xì)的介紹,需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助
    2014-03-03
  • JS實(shí)現(xiàn)簡(jiǎn)單加減購(gòu)物車(chē)效果

    JS實(shí)現(xiàn)簡(jiǎn)單加減購(gòu)物車(chē)效果

    這篇文章主要為大家詳細(xì)介紹了JS實(shí)現(xiàn)簡(jiǎn)單加減購(gòu)物車(chē)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • 正則中的回溯定義與用法分析【JS與java實(shí)現(xiàn)】

    正則中的回溯定義與用法分析【JS與java實(shí)現(xiàn)】

    這篇文章主要介紹了正則中的回溯定義與用法,結(jié)合實(shí)例形式分析了回溯的概念、功能并提供了JS與java實(shí)現(xiàn)方法,需要的朋友可以參考下
    2016-12-12
  • js實(shí)現(xiàn)支持手機(jī)滑動(dòng)切換的輪播圖片效果實(shí)例

    js實(shí)現(xiàn)支持手機(jī)滑動(dòng)切換的輪播圖片效果實(shí)例

    這篇文章主要介紹了js實(shí)現(xiàn)支持手機(jī)滑動(dòng)切換的輪播圖片效果,實(shí)例分析了javascript實(shí)現(xiàn)圖片切換的相關(guān)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2015-04-04
  • js實(shí)現(xiàn)文字選中分享功能

    js實(shí)現(xiàn)文字選中分享功能

    本文主要分享了js實(shí)現(xiàn)文字選中分享功能的示例代碼。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-01-01
  • javascript實(shí)現(xiàn)網(wǎng)頁(yè)背景煙花效果的方法

    javascript實(shí)現(xiàn)網(wǎng)頁(yè)背景煙花效果的方法

    這篇文章主要介紹了javascript實(shí)現(xiàn)網(wǎng)頁(yè)背景煙花效果的方法,涉及javascript數(shù)學(xué)運(yùn)算及頁(yè)面元素動(dòng)態(tài)操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-08-08

最新評(píng)論