摘要:構(gòu)造函數(shù)實(shí)例和原型的概念和關(guān)系每個(gè)函數(shù)都屬于對(duì)象,都會(huì)有一個(gè)屬性叫。這也是繼承的依據(jù)。這樣一來(lái),原型找不到構(gòu)造函數(shù),這是非常蛋疼的事情,違反了原型鏈的定義啊。所以現(xiàn)在子對(duì)象原型和父對(duì)象原型是就建立關(guān)系了。
構(gòu)造函數(shù)、實(shí)例和原型的概念和關(guān)系
每個(gè)函數(shù)都屬于對(duì)象,都會(huì)有一個(gè)屬性叫prototype。這個(gè)屬性指向一個(gè)對(duì)象,我們把他叫做當(dāng)前函數(shù)的原型對(duì)象。原型對(duì)象下面有個(gè)屬性叫constructor.這個(gè)屬性指向當(dāng)前函數(shù)。函數(shù)又分為普通函數(shù)和構(gòu)造函數(shù)。這里我們說(shuō)一下構(gòu)造函數(shù)。
定義一個(gè)函數(shù) :
function Person(x, y ) { this.age = x; this.name = y; } var xiaoming= new Person(12, "xiaoming" );
這里創(chuàng)建實(shí)例對(duì)象 xiaoming的時(shí)候就是調(diào)用了Person構(gòu)造函數(shù),使xiaoming有了自己的屬性和方法,之后xiaoming和Person也就沒(méi)有什么直接交集了(可以理解為小明分手了,哎程序員好難╥..╥)
但是每個(gè)實(shí)例對(duì)象都會(huì)有一個(gè)隱藏屬性[[prototype]],這個(gè)屬性在chrome/firefox下叫__proto__,僅僅供學(xué)習(xí)調(diào)試用.它指向的就是構(gòu)造函數(shù)的原型對(duì)象。
對(duì)于這個(gè)原型對(duì)象,我們就要重點(diǎn)理解下了。這個(gè)對(duì)象的作用就是為了讓所有的實(shí)例對(duì)象都能共享這個(gè)對(duì)象的屬性和方法(當(dāng)然實(shí)例本身的屬性和方法優(yōu)先級(jí)是高于原型的)。每個(gè)構(gòu)造函數(shù)都會(huì)有一個(gè)默認(rèn)的原型對(duì)象。我們只要在改原型對(duì)象上做文章就可以實(shí)現(xiàn)很多功能。
● 共享屬性和方法:
Person.prototype.eyes = 2; Person.prototype.walk = function ( ){……}; var xiaoming= new Person(12, "xiaoming" ); var xiaohong= new Person(12, "xiaohong" ); xiaoming.eyes xiaohong.eyes // 小明和小紅都有2只眼 xiaoming.walk xiaohong.walk //小明和小紅都會(huì)走路
● 原型鏈:
我們先做一個(gè)假設(shè),假如我們把一個(gè)函數(shù)對(duì)象Man的原型直接給換成另一個(gè)函數(shù)對(duì)象Person的實(shí)例對(duì)象xiaoming會(huì)怎么樣呢?
前面說(shuō)了,通過(guò)實(shí)例對(duì)象是可以找到函數(shù)對(duì)象Person的原型。那我們現(xiàn)在Man對(duì)象的實(shí)例xiaoming是不是也就可以訪(fǎng)問(wèn)到Person對(duì)象的原型對(duì)象了呢。
function Man( ) { this.beard = "xxx"; } Man.prototype = new Person( 23, "xiaoming" ); 這里我們相當(dāng)于把默認(rèn)的那個(gè)原型給重寫(xiě)了,給參數(shù)其實(shí)就是給原型添加屬性和方法 var xiaoming = new Man(); xiaoming.beard //xxx 這里實(shí)例xiaoming自己的屬性(小明有胡子) xiaoming.age //23 xiaoming.name //xiaoming 這兩個(gè)屬性是實(shí)例的原型上面的屬性(其實(shí)這個(gè)屬性是Person實(shí)例的屬性,但是現(xiàn)在的原型不就是Person實(shí)例嗎) xiaoming.eyes //2 這個(gè)屬性呢,是Person的原型對(duì)象上面的了
這里我們基本上都可以訪(fǎng)問(wèn)到,是不是有點(diǎn)繼承的味道了。
如果我們?cè)龠@樣搞一個(gè)對(duì)象,也這么干,這里是不是就感覺(jué)像條鏈一樣。最頂端的對(duì)象是Object,也就是說(shuō)到最后了。我們把這條鏈接方式叫做原型鏈。這也是繼承的依據(jù)。
和傳統(tǒng)的OOP語(yǔ)言來(lái)說(shuō),JavaScript語(yǔ)言比較蛋疼的是它沒(méi)有類(lèi)這個(gè)機(jī)制。所以說(shuō)我們事先js的繼承就從對(duì)象角度下手了。我們重點(diǎn)說(shuō)一下依據(jù)原型鏈繼承的。(其他的繼承我就不說(shuō)了,比如借用父對(duì)象的構(gòu)造函數(shù)等,實(shí)用性不強(qiáng))
1.上面所說(shuō)的實(shí)現(xiàn)原型鏈的方法雖然有點(diǎn)繼承的味道了,但是你有沒(méi)有發(fā)現(xiàn) 實(shí)例化xiaoming這個(gè)對(duì)象的時(shí)候調(diào)用了Man這個(gè)構(gòu)造函數(shù),但是xiaoming自己的age和name都沒(méi)能進(jìn)行構(gòu)造,只不過(guò)是原型上的屬性而已(其實(shí)是Person自己構(gòu)造的,new Person( 23, "xiaoming" ))。我們其實(shí)可以這樣用call和apply這個(gè)object原型下面給我們定義好的方法改進(jìn)下(call和apply方法自己看api說(shuō)明吧)
function Man(x, y) { Person.call(this, x, y); //這里你可以這樣理解,this指的是Man,這樣其實(shí)就是借用Person構(gòu)造函數(shù) this.beard = "xxx"; }
我們把Man的構(gòu)造函數(shù)這樣一改,實(shí)例化的時(shí)候傳參,這樣age和name這兩個(gè)屬性就是Man自己構(gòu)造出來(lái)的了,并不會(huì)被共享
Man.prototype = new Person( ); Man.prototype.constructor = Man; var xiaoming = new Man(23, "xiaoming");
這里只是讓Man的原型的構(gòu)造函數(shù)變成原有的構(gòu)造函數(shù),如果不加這一句的話(huà),那么Man原型的構(gòu)造函數(shù)就變成undefied,因?yàn)閷?shí)例和構(gòu)造函數(shù)并沒(méi)有直接關(guān)系。這樣一來(lái),原型找不到構(gòu)造函數(shù),這是非常蛋疼的事情,違反了原型鏈的定義啊。
這邊可能會(huì)有人問(wèn)了,我為什么不自己像胡子beard 那個(gè)屬性一樣直接構(gòu)造呢。
大哥,我這是舉例子,你以為實(shí)際的項(xiàng)目中就會(huì)有這么兩個(gè)屬性嗎。而且這樣不正是繼承的目的嗎
可以少寫(xiě)很多代碼啊。(說(shuō)多了都是淚)
但是也是有缺點(diǎn)的:兩次調(diào)用父類(lèi)構(gòu)造函數(shù)(第一次是在創(chuàng)建子類(lèi)原型的時(shí)候,第二次是在子類(lèi)構(gòu)造函數(shù)內(nèi)部);子類(lèi)繼承父類(lèi)的屬性,一組在子類(lèi)實(shí)例上,一組在子類(lèi)原型上(在子類(lèi)原型上創(chuàng)建不必要的多余的屬性,實(shí)例上的屏蔽原型上的同名屬性,是不是感覺(jué)有點(diǎn)多余了 ,效率低。
2.為了改進(jìn)這種方法,下面說(shuō)的這種繼承方式是借助我們偉大的道爺(這個(gè)人很厲害,自行百度)的靈感 。這種就是利用一個(gè)空函數(shù)對(duì)象來(lái)做一個(gè)橋梁.
具體實(shí)現(xiàn)方式如下:
function inherits(Child, Parent) { var F = function () {}; F.prototype = Parent.prototype; Child.prototype = new F(); Child.prototype.constructor = Child; }
另外在子對(duì)象的構(gòu)造函數(shù)中別忘了借用父對(duì)象的構(gòu)造函數(shù)哦。(就是那個(gè)call或者apply方法)
這里和上面的區(qū)別是,子對(duì)象的原型現(xiàn)在不是父對(duì)象的實(shí)例了,變成了空函數(shù)對(duì)象的實(shí)例(父對(duì)象不用再創(chuàng)建兩次了,并且子對(duì)象的原型上也不會(huì)有啥屬性和方法了)。而空函數(shù)對(duì)象的原型變成了父對(duì)象的原型。前面我們說(shuō)過(guò),有了實(shí)例就能找到原型。所以現(xiàn)在子對(duì)象原型和父對(duì)象原型是就建立關(guān)系了。這種方式現(xiàn)在是最穩(wěn)的方法,也已經(jīng)被很多框架給寫(xiě)到源碼里面了。
這里我們就用google closure 關(guān)于繼承的兩個(gè)api,這邊簡(jiǎn)單舉個(gè)例子:
Child = function( ){ goog.base(this); this.height = 12; } goog.inherits(Child, Parent);
這里就實(shí)現(xiàn)了我們上述實(shí)現(xiàn)的,不過(guò)封裝起來(lái)了而已。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/91355.html
摘要:之前有朋友問(wèn)怎么去理解原型和原型鏈的問(wèn)題。理解原型鏈的小技巧將箭頭視作泛化子類(lèi)到父類(lèi)關(guān)系那么圖中所有的虛線(xiàn)將構(gòu)成一個(gè)繼承層級(jí),而實(shí)線(xiàn)表示屬性引用。原型鏈?zhǔn)菍?shí)現(xiàn)繼承的重要方式,原型鏈的形成是真正是靠而非。 之前有朋友問(wèn)怎么去理解原型和原型鏈的問(wèn)題。這個(gè)問(wèn)題,在面試中,很多同學(xué)經(jīng)常都會(huì)遇到。這里給大家講講,方便大家記憶。 JavaScript的特點(diǎn)JavaScript是一門(mén)直譯式腳本...
摘要:之前有朋友問(wèn)怎么去理解原型和原型鏈的問(wèn)題。理解原型鏈的小技巧將箭頭視作泛化子類(lèi)到父類(lèi)關(guān)系那么圖中所有的虛線(xiàn)將構(gòu)成一個(gè)繼承層級(jí),而實(shí)線(xiàn)表示屬性引用。原型鏈?zhǔn)菍?shí)現(xiàn)繼承的重要方式,原型鏈的形成是真正是靠而非。 之前有朋友問(wèn)怎么去理解原型和原型鏈的問(wèn)題。這個(gè)問(wèn)題,在面試中,很多同學(xué)經(jīng)常都會(huì)遇到。這里給大家講講,方便大家記憶。 JavaScript的特點(diǎn)JavaScript是一門(mén)直譯式腳本...
摘要:相當(dāng)于在用原型繼承編寫(xiě)復(fù)雜代碼前理解原型繼承模型十分重要。同時(shí),還要清楚代碼中原型鏈的長(zhǎng)度,并在必要時(shí)結(jié)束原型鏈,以避免可能存在的性能問(wèn)題。 js是一門(mén)動(dòng)態(tài)語(yǔ)言,js沒(méi)有類(lèi)的概念,ES6 新增了class 關(guān)鍵字,但只是語(yǔ)法糖,JavaScript 仍舊是基于原型。 至于繼承,js的繼承與java這種傳統(tǒng)的繼承不一樣.js是基于原型鏈的繼承. 在javascript里面,每個(gè)對(duì)象都有一...
摘要:在節(jié)中,我們學(xué)習(xí)到了通過(guò)構(gòu)造函數(shù)創(chuàng)建對(duì)象的三個(gè)重要步驟,其中的一步是把構(gòu)造函數(shù)的對(duì)象設(shè)置為創(chuàng)建對(duì)象的原型。利用而不是直接用創(chuàng)建一個(gè)實(shí)例對(duì)象的目的是,減少一次調(diào)用父構(gòu)造函數(shù)的執(zhí)行。 JavaScript語(yǔ)言不像面向?qū)ο蟮木幊陶Z(yǔ)言中有類(lèi)的概念,所以也就沒(méi)有類(lèi)之間直接的繼承,JavaScript中只有對(duì)象,使用函數(shù)模擬類(lèi),基于對(duì)象之間的原型鏈來(lái)實(shí)現(xiàn)繼承關(guān)系,ES6的語(yǔ)法中新增了class關(guān)鍵...
摘要:原型對(duì)象是由創(chuàng)建的,因此原型對(duì)象的構(gòu)造函數(shù)是構(gòu)造函數(shù)也可以是稱(chēng)為對(duì)象,原型對(duì)象也就繼承了其生父構(gòu)造函數(shù)中的數(shù)據(jù),也同時(shí)繼承了原型對(duì)象的數(shù)據(jù)。當(dāng)然這條原型鏈中的數(shù)據(jù),會(huì)被還是還是這類(lèi)構(gòu)造函數(shù)繼承,但是不會(huì)被這些繼承,他們不處于同一個(gè)鏈條上。 js中,F(xiàn)unction的本質(zhì)是什么?Object的本質(zhì)又是什么?js中有幾條原型鏈? showImg(https://segmentfault.c...
閱讀 924·2021-09-09 09:32
閱讀 2898·2021-09-02 10:20
閱讀 2711·2021-07-23 11:24
閱讀 838·2019-08-30 15:54
閱讀 3640·2019-08-30 15:54
閱讀 1353·2019-08-30 11:02
閱讀 2855·2019-08-26 17:40
閱讀 1136·2019-08-26 13:55