少俠們好先较,
上次和大家聊了一些關(guān)于this的故事携冤,在最后,我們也說了闲勺,還有一些相關(guān)的內(nèi)容和問題沒有談到曾棕,
比如,prototype原型鏈菜循,
不管是在你閱讀文章翘地,還是面試時,可能都會被問到關(guān)于它的問題癌幕。
如果少俠你看過關(guān)于它的文章衙耕,
你很可能已經(jīng)見過一些和它相關(guān)的字眼,prototype勺远,_proto_橙喘,new,this 等等胶逢。
但是厅瞎,即使你對這些字眼都很熟悉了,你可能也會有一個疑惑宪塔,
原型鏈到底是什么磁奖? 到底是怎么來的,又有什么作用呢某筐?
為了弄清楚它比搭,在這次的故事中,我們會先講述一些關(guān)于對象其他的內(nèi)容,這些內(nèi)容能夠幫我們最終過渡到原型鏈去身诺,并真正了解它做了什么蜜托。
它們可能與原型鏈無關(guān),但是以后卻能夠幫助你更好的理解原型鏈霉赡。
這就是為什么我們的標題會是
prototype前傳
好了橄务,下面開始進入正題~
冰山之下
少俠,如果你看過上一節(jié)關(guān)于 this 的故事的話穴亏,你應(yīng)該已經(jīng)知道蜂挪,之所以會有 this 存在,其實就是因為我們需要有這樣一個動態(tài)的東西嗓化。
用來干嘛呢棠涮? 用來做對象組合,這樣我們就可以復用和組合現(xiàn)成的對象刺覆,來完成新的功能严肪。
了解事物的本質(zhì)這一點非常非常重要,
比如你知道了 this 出現(xiàn)的原因就是為了動態(tài)組合對象谦屑,所以它會動態(tài)的變來變?nèi)ヒ簿筒黄婀至恕?/p>
原型鏈也是一樣驳糯,理解它的關(guān)鍵點就在于弄清楚它的本質(zhì)是什么,實際上氢橙,它的本質(zhì)和 new 沒有什么必然的關(guān)系酝枢,和所謂的_proto_ 也沒有太大的關(guān)系,
它的本質(zhì)是對象組合充蓝。
我們可以有多種方式來組合對象隧枫,組合方式的不同,就構(gòu)成了一個個不同的方法谓苟,
原型鏈就是其中之一官脓,
除了它之外,也還有很多其他的方式涝焙,
所以今天卑笨,我們先不說原型鏈,說一說其他的組合方式~
首先仑撞,來看看我們上次的一個例子:
在這里赤兴,我們有一個 user 對象,里面包含了 user 的名稱隧哮,寵物列表桶良,以及兩個對應(yīng)的方法,一個用來獲取名稱沮翔,另一個用來添加寵物陨帆。
這種對象,大多數(shù)情況是沒有什么問題的,你可以很方便的把相關(guān)的邏輯放在一起來使用,
不過疲牵,這種方式承二,有時候也會不太容易復用和組合,
因為它只是很簡單的把數(shù)據(jù)和行為混合在了一起纲爸,會顯得有點 too young too simple,
所以亥鸠,我們來試著把數(shù)據(jù)和行為單獨放在不同的對象里。
分開很簡單识啦,不過负蚊,光分開是沒有用的,在合適的時候颓哮,我們得想辦法把它們再組合起來才行盖桥,因為光有數(shù)據(jù)的話,就好比少俠你有一大筆錢题翻,卻找不到花錢的地方,而光有行為的話腰鬼,就好比少俠你可以花錢如流水嵌赠,但是,賬上沒有流水熄赡。姜挺。。
所以彼硫,它們得組合在一起才能完全發(fā)揮出作用炊豪。
怎么組合呢?
第一種組合的方式拧篮,在上節(jié)關(guān)于 this 的故事中词渤,少俠你其實已經(jīng)遇見過了,就是我們在使用 Object.assign 時的方式串绩,它也叫做 mixin缺虐。
Mixin
Mixin 是最簡單的合并對象的方式,通過將一個對象中的屬性復制到另外一個對象中來實現(xiàn)合并礁凡。
在這里高氮,我們通過自定義的 mixin 函數(shù)把 userActions 里面的方法混入到了 user 中。
當然顷牌,使用內(nèi)置的 Object.assign 可能會好一些:
少俠你可以看到剪芍,通過 mixin , 我們的 user 對象獲得了 userActions 中的方法。
mixin 的好處是你可以把 userActions 同時混入多個對象窟蓝,來達到方法復用的效果罪裹。
mixin 的方式有幾個特點,
第一個特點是 mixin 處理對象的方式屬于 early-bound
什么意思呢? 意思是結(jié)果對象中的方法在經(jīng)過 mixin 處理時就已經(jīng)確定了坊谁,即使你會過后才調(diào)用它费彼,但是它是在 mixin 那一刻就已經(jīng)確定了。
比如這里我們將 userActions 混入到 user 中口芍,user 中的 getName 或是 addPets只會取決于混入這一刻時 userActions 中的對應(yīng)方法箍铲,混入完成后,即使我們過后改變 userActions 中 getName 方法鬓椭,對 user 也不會有任何影響颠猴。
這就是 early-bound,也就是說小染,會調(diào)用哪個函數(shù)翘瓮,在一開始的時刻就已經(jīng)確定好了,所以是 early裤翩。
第二個特點是通過 mixin 處理的對象资盅,最終所有的效果都會在我們的接收者上發(fā)生。
比如踊赠,我們把 userActions 混入到 user 之后呵扛,user 就是接收者,當我們調(diào)用 user.getName 方法時筐带,它會去查找 user 上的 name今穿,不會對 userActions 造成任何影響,只和它本身有關(guān)伦籍,就算你把 userActions 銷毀了蓝晒,設(shè)置為 null,也沒關(guān)系帖鸦。
“天辰芝薇,這不是廢話嗎?我都把方法放在它里面了富蓄,也已經(jīng)混入完成了剩燥,調(diào)用時不和它有關(guān),難道還和你有關(guān)立倍?”
“對啊灭红,這不很明顯嘛?有什么好說的口注”淝埽”
沒錯,這里是很明顯寝志,也是 mixin 的特點娇斑,
但是策添,在另外的組合方式下,情況可能就完全不一樣了毫缆!
比如接下來我們要說的 forward 方式唯竹。
Forward
另外一種對象組合的方式是 forward,它和我們的 mixin 區(qū)別有點大苦丁,因為浸颓,它既不是 early-bound,作用的效果也不是在接收者上旺拉。
我們接著上面的例子來看吧产上,想象少俠你已經(jīng)通過 mixin 把 userActions 混入到 user 中了,
然后蛾狗,現(xiàn)在我們遇見了新情況晋涣,一個寵物店,它可以讓我們捐獻寵物沉桌,
假設(shè)這是我們的寵物店對象:
如果你想給寵物店捐獻寵物的話谢鹊,
如何將我們的 user 對象和寵物店關(guān)聯(lián)起來呢?
這種情況留凭,少俠你不能使用 mixin(user, petStore)的方式撇贺,
除非。冰抢。。少俠你想把自己變成一個寵物店艘狭。挎扰。。
這時巢音,我們就需要另外一種組合方式遵倦,
也就是 forward !
它可以讓我們將另一個對象上的方法組合進來官撼,并且當你調(diào)用這些方法時梧躺,它會在原來的對象上發(fā)揮作用。
類似這樣:
那么 forward 長什么樣呢傲绣?
見證奇跡的時刻掠哥!
我們來試試用 forward 把 petStore 整合進來:
好了,少俠應(yīng)該已經(jīng)發(fā)現(xiàn) forward 的區(qū)別了秃诵,在這里续搀,我們希望 userActions 中的方法作用于 user 本身,于是我們采用mixin菠净,
但是我們卻希望 petStore 上的方法作用于 petStore 本身禁舷,只不過可以在 user 上調(diào)用彪杉,我們則采用了 forward。
所以我們可以使用 user.addPet 給 user 內(nèi)部的 pets 添加寵物牵咙,然后使用 user.givePet 給 petStore 內(nèi)部的 pets 添加寵物派近。
很神奇是吧?
我們還可以把多個用戶和同一個寵物店關(guān)聯(lián)起來:
在這里洁桌,我們通過 forward 函數(shù)渴丸,同時把 petStore 關(guān)聯(lián)到了兩個不同的用戶上,
然后战坤,user1 和 user2 會共享同一個 petStore曙强,也就是,你通過 user 添加一個寵物途茫,再通過 user2 添加一個寵物碟嘴,petStore 上會有2個寵物,這些數(shù)據(jù)針對所有用戶都是同步的囊卜。
“哦娜扇,這樣啊,那么共享的數(shù)據(jù)有什么用處呢栅组?”
“對雀瓢,我又不開寵物店,換個另外的例子玉掸!”
具體的用途的話刃麸,不同的少俠會有不同的理解,就像它本身體現(xiàn)的特點一樣司浪,如果有一些數(shù)據(jù)你想在多個不同的對象之間共享泊业,也許你就可以試試這種方式。
當然啊易,天辰我人比較好吁伺,
所以這里我就再給少俠你舉個簡單例子了,比如你頁面自定義了一個路由棧:
很明顯的是租谈,路由對于所有的頁面應(yīng)該是共享的篮奄,不管哪個頁面返回了一級,對于的路由棧就應(yīng)該減少一層割去,所以我們使用了 forward 來將路由方法共享到每個頁面中窟却。
early-bound 與 late-bound
上面我們提到過, mixin 是 early-bound呻逆,意思是间校,一旦混入了一些方法,就算我們過后改變了源對象中的方法页慷,也不會對已經(jīng)混入后的對象有所影響憔足。
那么 late-bound 又是什么意思呢胁附?
繼續(xù)我們的 forward 旅程,在之前滓彰,我們已經(jīng)和寵物店建立了合作關(guān)系:
但是控妻!現(xiàn)在由于天辰捐贈的小貓 藍胖dreamer 過于調(diào)皮,所以揭绑,寵物店決定暫時不接受繼續(xù)捐贈叫做藍胖的小貓了弓候。
好了,現(xiàn)在寵物店更新了新規(guī)則他匪,那么我們之前 forward 的方法還有用嗎菇存? 是需要我們手動再 forward 一次,還是會自動更新呢邦蜜?
我們來試一試
很神奇依鸥!
我們并不需要重新進行 forward ,當我們改變了 petStore 中的方法時悼沈,對應(yīng) user 中的方法會自動更新贱迟!這點和 mixin 不一樣,如果是 mixin 的話絮供,我們必須重新 mixin 一次才有效衣吠。
為什么會這樣呢?
原因是 forward 中下面這段代碼:
這里的關(guān)鍵點在于壤靶,我們并沒有直接把 petStore.givePet 賦值給 user缚俏,而是利用了一個中間的箭頭函數(shù)。
這樣的話贮乳,在一開始袍榆,user.givePet 只是和這個箭頭函數(shù)聯(lián)系了起來,它并不會馬上就繼續(xù)去查看箭頭函數(shù)里面的內(nèi)容,畢竟箭頭函數(shù)都還沒有調(diào)用對吧宿崭?
也就是說亲铡,到我們真正調(diào)用這個箭頭函數(shù),并開始查找其中的 petStore.givePet 之間的時間段葡兑,我們是可以改變 petStore.givePet 方法的奖蔓。
在這之間,不管中途 givePet 變換了多少次讹堤,就算它有一段時間變成 undefined吆鹤,null 等等也沒有關(guān)系,因為只要我們不觸發(fā)箭頭函數(shù)洲守,它就不會去查找 petStore.givePet疑务。
它過去是什么不重要沾凄,重要的是,我們找到它時知允,它是什么撒蟀。
汝未看此花時,此花與汝同歸于寂温鸽。汝來看此花時保屯,此花顏色一時明白過來。便知此花不在汝之心外涤垫」贸撸——王陽明
好了,這就是 early-bound 和 late-bound 的區(qū)別了蝠猬,一個是在最開始就決定好調(diào)用哪個函數(shù)了切蟋,另一個則是在調(diào)用時,才開始查找調(diào)用哪個函數(shù)吱雏。
總結(jié)一下~
組合方式 | bound 類型 | 方法中的作用對象 | 數(shù)據(jù)是否獨立 |
---|---|---|---|
mixin | early-bound | 對象本身 | 是敦姻,每個對象的操作不會影響其他 mixin 對象 |
forward | late-bound | 用于組合的對象 | 否,用于所有對象會共享 forward 進來的對象數(shù)據(jù)歧杏,所以會互相影響 |
完全OK!
恭喜你镰惦,少俠~
你又成功發(fā)現(xiàn)并閱讀完了一篇非常有趣的文章!
希望能夠?qū)δ阌兴斋@~
可惜的是犬绒,我們依然還沒有說到 prototype 旺入,
而且你可能也還有一些疑問,
沒有關(guān)系凯力,
以后還會有很多有趣的內(nèi)容會提到的茵瘾,
如果少俠你覺得以上內(nèi)容對你有幫助的話,
希望可以幫忙給分享或點個贊咐鹤,
讓我感受一下江湖的溫暖~
好了拗秘,江湖路遠,少俠我們有緣再見~
一些你可能關(guān)心的問題
1祈惶、等了這么久的prototype原型鏈胸私,結(jié)果天辰你告訴我還有前傳恒削?
別急民晒,少俠些己,前傳通常能夠幫助你更好的了解劇情,這里也是一樣疹蛉,相信我活箕,這樣的路線也許能夠幫你更好的過渡到原型鏈,而且可款,說不定我們一不小心就實現(xiàn)它了育韩,還順帶解鎖一堆隱藏的小伙伴呢~
2克蚂、好吧,老實說座慰,forward 的實現(xiàn)有點沒看懂陨舱。。版仔。
哈哈哈哈游盲,我就知道(突然出現(xiàn)的迷之優(yōu)越感),少俠你可以這樣對比 mixin 和 forward:
我們上面的 forward 函數(shù)只不過多了自動檢測 obj2 中的方法蛮粮,并批量賦值這么一個過程益缎。
真正的關(guān)鍵點,就是一個多了一個中間箭頭函數(shù)然想,另外一個沒有莺奔。
注意了,少俠! 請你認真仔細的觀察它們的區(qū)別变泄,多測試一下令哟,找找不同點~
3、為什么 obj1.fn = () => { obj2.fn(); } 會在箭頭函數(shù)調(diào)用時再去查找 obj2.fn妨蛹,而直接賦值 obj1.fn = obj2.fn 卻不在調(diào)用 obj1.fn 時再去查找 obj2 中的 fn 呢
我就知道有人可能會有這個疑問屏富!
這個問題實際上和 JS 中的賦值運算有關(guān)。
本來打算就這里說了蛙卤,不過發(fā)現(xiàn)內(nèi)容稍微有點長狠半,就下次出單獨的專題說!
少俠你可以先自行思考下颤难,或者查找一下網(wǎng)上的資源神年,留給你當做練習題。
tip: 可以再參考一下上個問題中的流程行嗤。
4已日、接下來是不是要開始說關(guān)于prototype原型鏈的故事了?
不知道! 生活總是會給你帶來驚喜栅屏,我也是飘千!不能隨便透露下面的內(nèi)容,甚至下一次說的還是不是 JavaScript 都不一定既琴,所以,別亂猜了泡嘴,少俠甫恩,直接點贊關(guān)注加轉(zhuǎn)發(fā)~
5、藍胖dreamer 是個什么鬼酌予? 真的是只調(diào)皮的寵物嗎磺箕?
當然是真的寵物奖慌,不過,現(xiàn)實中的它一點也不調(diào)皮松靡!反而很聽話~
下一篇文章爭取給它爆個照简僧!
6、干嘛要在名稱后面加個 dreamer 雕欺?
之前以為 dreamer 的意思是幻想家岛马,像是形容那些懷揣夢想的人,感覺很酷屠列,但是后來知道了它的意思其實也有不切實際的人啦逆,看起來很奇怪, 既有褒義又有貶義笛洛,后來我想了下夏志,也許 dreamer 在一開始本身就是不好不壞的,與其在一開始去糾結(jié)它的意思苛让,倒不如選擇成為一個 dreamer沟蔑,親自去定義它。
Be a dreamer, not a loser. 少俠~
聲明:本文僅限于瀟灑有趣又很酷的天辰dreamer裝逼使用狱杰,轉(zhuǎn)載請注明原作者和出處瘦材,商業(yè)轉(zhuǎn)載請聯(lián)系我(如果真有的話)。浦旱。宇色。