前端基本知識:JS的原始鏈的理解
一、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的原始鏈的理解