1. 程式人生 > >前端基本知識:JS的原始鏈的理解

前端基本知識:JS的原始鏈的理解

這也 car tro 訪問 address script 解釋 owa res

一、JS的原型鏈理解方式

二、原型理解

三、規則

四、js常見的創建對象的各種方法

一、原始鏈理解方式

每一次原型鏈理解起來很費勁,而且經常容易出錯,或者解釋的不到位。

1、什麽是對象實例,什麽是原型(對象)?

2、什麽是構造函數?

3、通過原型對象找到構造函數

4、原型的唯一性

5、原型鏈

6、原型鏈最終指向為null

7、繼承

8、原型鏈的繼承

9、原型鏈的向上搜索

10、對象的屬性可以自定義

11、對象實例不能改動原型屬性

12、原型屬性的共享

13、原型的動態性

14、原型的重寫

我去,這也太多了,不想看了,我已經蒙圈了。等等,學習本身就是一個痛苦的過程,但是當你通過自己的理解的東西,這樣運行機制就更容易理解。

你可以這樣理解:

1、”人是人生的,妖是妖生的。“人和妖都是對象實例,人他媽和妖他媽都是原型,也叫原型對象。

2、“人出生和妖出生”都是構造一個函數,從無到有的過程

3、“人可以通過人他媽找到人他爸是誰”,也就是通過原型找到構造函數。

4、“人他媽可以生很多小寶寶,但是這些寶寶只有一個媽媽”,這就是原型的唯一性。

5、“人他媽的媽媽,和人他媽的媽媽的媽媽,。。。。”,這就是原型鏈

6、原型鏈並不是無限長,通過繼承可以不斷的往上找,最終原型鏈指向null

7、“人繼承了人他媽的屬性,妖繼承了妖他媽的屬性。”

8、“人繼承了人他媽的膚色等等,人他媽繼承人他媽他媽的膚色等等。。。”這就是原型繼承。

9、“你沒有家,你家指的就是你媽家;你媽沒有家,那你家指向的就是你媽媽的媽媽的家“,這就是原型鏈的向上搜索。

10、“你會繼承你媽的樣子,但是你可以染發剪頭發等等”,也就是說對象的屬性可以的自定義。

11、"雖然你改變了自己的頭發顏色等等,但是你不能改變你媽的樣子",這就是對象實例不能改變原型的屬性。

12、“你家玩火被你說了話,那就是說你家,你媽家,你弟弟們家,都被少了,這就是原型共享”

13、“你媽外號叫"小翠",鄰居都叫你“小翠兒”,但是你媽做了一個帥氣的發型,外號改成了“金毛獅王”,鄰居都叫你,“金毛獅王子””,這就是原型的動態性。

14、“你媽愛美,整容了,沒有人認識,然後又整回去了”,這就是叫原型的整體重寫。

在用代碼說明原型鏈的之前,我們先弄清楚,函數和function有什麽關系,構造函數,原型,實例之間有什麽關系?

答:1、所有的函數都是 Function的實例。

2、在構造函數上都有一個原型屬性 prototype,該屬性也是一個對象;

3、那麽在原型對象上有一個 constructor屬性,該屬性指向的就是構造函數;

4、而實例對象上有一個 _proto_屬性,該屬性也指向原型對象,並且該屬性不是標準屬性,不可以用在編程中,該屬性用於瀏覽器內部使用。

function person(name){this.name=name} function mother{} mother.prototype={//mother原型自帶屬性prototype age:20, home:[‘Beijing‘,‘Shanghai‘] }; person.prototype=new mother; //person的原型為mothervar p1=new person(‘Tom‘); //p1:‘Tom‘;_proto_:20,[‘Beijing‘,‘Shanghai‘]var p2=new person(‘Mark‘) //p2:‘Mark‘;_proto_:20,[‘Beijing‘,‘Shanghai‘] p1.age=24; //實例不能改變原型的基本屬性值,在p1實例下增加一個age的屬性,與原型無關 //p1:‘Tom‘,24;_proto_:20,[‘Beijing‘,‘Shanghai‘] p1.home[0]=‘Shenzhen‘; //原型中引用類型屬相的共享,,正如你燒了你家,就是燒了你全家的家 //p1:‘Tom‘,24;_proto_:20,[‘Shenzhen‘,‘Shanghai‘] //p2:‘Mark‘;_proto_:20,[‘Shenzhen‘,‘Shanghai‘] p1.home=[‘Hangzhou‘,‘Guangzhou‘]; //其實與p1.age=20的操作一樣 //p1:‘Tom‘,24,[‘Hangzhou‘,‘Guangzhou‘];_proto_:20,[‘Shenzhen‘,‘Shanghai‘] //delete p1.age; //刪除自定義的屬性之後,原本覆蓋的原型就可以重見天日,這就是搜索機制 //p1:‘Tom‘,[‘Hangzhou‘,‘Guangzhou‘];_proto_:20,[‘Shenzhen‘,‘Shanghai‘] // person.prototype.lastname=‘Cheng‘; //改寫原型,動態反應在實例中。我們改寫的是person的原型,往mother裏加一個last那麽屬性 //等同於mother.lastname=‘Cheng‘ //這裏並不是mother。prototype,改動不同的層次,效果會有很大的差異 //p1:‘Tom‘,[‘Hangzhou‘,‘Guangzhou‘];_proto_:‘Cheng‘;_proto_:20,[‘Shenzhen‘,‘Shanghai‘] //p2:‘Mark‘,[‘Hangzhou‘,‘Guangzhou‘];_proto_:‘Cheng‘;_proto_:20,[‘Shenzhen‘,‘Shanghai] person.prototype={ age:28, address:{country:‘USA‘,city:‘Washington‘} }; var p3=new person(‘obama‘); //重寫原型,這個時候person的原型完全改變 // //p2:‘Mark‘,[‘Hangzhou‘,‘Guangzhou‘];_proto_:‘Cheng‘;_proto_:20,[‘Shenzhen‘,‘Shanghai‘] //p3:‘obma‘;_proto_:28{country:‘USA‘,city:‘Washington‘} mother.prototype.no=20110408; //改寫原型的原型,動態反應在實例中, //p1和p2會改變,但是p3不會改變,p3與mother無關 //p1:‘Tom‘,[‘Hangzhou‘,‘Guangzhou‘];_proto_:‘Cheng‘;_proto_:20,[‘Shenzhen‘,‘Shanghai‘],20110408 //p2:‘Mark‘,[‘Hangzhou‘,‘Guangzhou‘];_proto_:‘Cheng‘;_proto_:20,[‘Shenzhen‘,‘Shanghai‘],20110408 //p3:‘obama‘;_proto_:28{country:‘USA‘,city:‘Washington‘} mother.prototype={ car:2, hobby:[‘run‘,‘walk‘] }; var p4=new person(‘Tony‘); //重寫原型的原型,這時候mother的原型已經發生完全的變化 //上面的person和mother已經斷開聯系了,mother怎麽變都不會影響person //p4:‘Tony‘;_proto_:28{country:‘USA‘,city:‘Washington‘} person.prototype=new mother; //再次綁定var p5=new person(‘Luccy‘); //這個時候如果需要應用這邊改動的話,需要重新將person原型綁定在mother上 //p5:‘Luccy‘;_proto_:2,[‘run‘,‘walk‘] p1.__proto__.__proto__.__proto__.__proto__ //null,原始鏈終點是null mother.__proto__.__proto__.__proto__ //null ,原型鏈的終點事null

二、原型理解

javascript中,原型也是一個對象,通過原型可以實現對象的屬性繼承,javascript的對象中都包含了一個protype內部屬性,這個屬性對應的就是該對象的原型。javascript的原型對象中還包含一個constructor屬性,這個屬性對應創建所有指向該原型的實例的構造函數。

註意:protype作為對象的內部屬性是不可以直接訪問的,但是谷歌瀏覽器提供了一個_proto_這個非標準的訪問器。

三、規則

javascript中,每一個函數都有一個prototype屬性,當一個函數被用作構造函數來創建實例,這個prototype屬性值會被作為原型賦值給所有的對象實例(也就是所有實例設置“_proto_”屬性)。

對象:prototype屬性

原型對象:protype屬性,construction屬性

對象實例:_proto_屬性

new的過程分為三步:

var p=new person(‘張三‘,20);

1、var p={};初始化一個對象p

2、p._proto_=person.prototype;將對象p的_proto_屬性設置為person.prototype

3、person.call(‘張三‘,20);調用構造函數person來初始化p。

原型鏈繼承的主要問題在於屬性的共享。原型繼承的改良方法:

(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); //第二次執行this.name=name; } person.prototype=new mother; //第一次執行 person.protype.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‘]varp2=new person(‘mark‘,18); //p2:‘mark‘;_proto_:18,[‘running‘,‘football‘]

執行結果如圖所示:

技術分享

技術分享

四、js常見的創建對象的各種方法

(1)原始模式

代碼重用量大,所以產生了工廠模式。

(2)工廠模式

工廠模式就是批量成產,效率

(3)構造函數

構造函數與c++,、java構造函數類似,易於理解。

(4)原型方式

這裏需要註意的是原型屬性和方法的共享,即所有實例中都只是引用原型中的屬性方法,任何一個地方差生的改動都會引起其他實例的變化。

前端基本知識:JS的原始鏈的理解