
少俠們好~
又是一段時(shí)間沒(méi)見(jiàn)了,新的一年了,希望各位少俠最近過(guò)得都還好。
上次和大家說(shuō)到了對(duì)象組合中的 mixin 和 forward,
本來(lái)按道理這次應(yīng)該繼續(xù)對(duì)象組合的話(huà)題聊下去,
但是!
由于接下來(lái)的內(nèi)容會(huì)稍微更復(fù)雜一些,
同時(shí)我想著有些少俠出于某些奇怪的原因,根基可能不太穩(wěn)。
再加上上次結(jié)尾說(shuō)了讓你們別猜,猜不到的,有些人應(yīng)該不信!
所以,這次的內(nèi)容中的 JS 知識(shí)可能是次要的,更重要的是和大家分享一些小思想和經(jīng)驗(yàn),
畢竟某個(gè)具體的 JS 知識(shí)點(diǎn)可能只能幫助少俠你解決某個(gè) JS 問(wèn)題,而一些通用的小套路可能會(huì)在多個(gè)領(lǐng)域?qū)δ阌袔椭?/p>
從標(biāo)題少俠你應(yīng)該也知道了,這次我們的內(nèi)容會(huì)和一些基礎(chǔ)知識(shí)有關(guān),一些你可能都不會(huì)怎么放在心上的內(nèi)容,但是,如果你輕易的忽視它們,在關(guān)鍵時(shí)刻,它們卻會(huì)對(duì)你產(chǎn)生蝴蝶效應(yīng)般的作用,而你甚至都意識(shí)不到這一點(diǎn)。
所以,這次的內(nèi)容可以算是一半技術(shù)文章,更重要的是思想~
tip:這篇文章是接著上一篇文章寫(xiě)的,最好是按順序看過(guò)來(lái)的比較好。
上一篇鏈接:
回到起點(diǎn),深入理解簡(jiǎn)單事物
一般來(lái)說(shuō),不管做什么,深入理解簡(jiǎn)單基礎(chǔ)的事物都是很重要的。
只有深入理解了基礎(chǔ)事物,才能更好的應(yīng)對(duì)在此這上更復(fù)雜的情況。
所以這里我們就聊一點(diǎn)容易被忽視的基礎(chǔ)知識(shí),
在 JS 中也一樣,總有一些最基礎(chǔ)必不可少的東西。
這里我們要聊到的是值。
什么是值呢?
值可以看做是 JS 中的最基礎(chǔ)的元素,就像我們世界中的基礎(chǔ)元素,氫元素,氧元素等等,
而在 JS 世界中,這些元素就是字符串,數(shù)字,布爾值等等。

除此之外,還有一些稍微復(fù)雜一些的元素,
比如對(duì)象,數(shù)組,以及函數(shù)等等。

知道了值之后,另外一個(gè)和它息息相關(guān)的內(nèi)容是表達(dá)式。
什么是表達(dá)式呢? 簡(jiǎn)單來(lái)說(shuō),能夠直接轉(zhuǎn)化成值的東西,就叫做表達(dá)式。
記住了,少俠,表達(dá)式可以直接轉(zhuǎn)化變成一個(gè)值,但是它并不是一個(gè)值。

這次的內(nèi)容很簡(jiǎn)單吧?
沒(méi)錯(cuò),都是基礎(chǔ)知識(shí),我們接著來(lái)看另外一個(gè)內(nèi)容,賦值。
這個(gè)時(shí)候可能會(huì)稍微有趣一些了,因?yàn)橘x值雖然比較簡(jiǎn)單,但是正因?yàn)樗容^簡(jiǎn)單,反而會(huì)讓少俠你很容易就忽略掉一些重要的東西。
你可以給一個(gè)變量賦值:

給一個(gè)對(duì)象屬性賦值:

還可以給一個(gè)數(shù)組賦值:

那么問(wèn)題來(lái)了,
少俠你有沒(méi)有想過(guò),當(dāng)你給一個(gè)變量,或者對(duì)象屬性賦值時(shí), 你到底是在往里面放什么東西,
或者說(shuō),你應(yīng)該在右邊放什么東西?
當(dāng)然是一個(gè)值了對(duì)吧? 你不可以說(shuō),我在變量里面放一個(gè)運(yùn)算符,比如 + 號(hào)。

你也不能直接放各種語(yǔ)句,至少在 JS 里面不能:

你可以放的只有值:

But! 生活總會(huì)有意外情況~
有時(shí)候,右邊會(huì)是一個(gè)表達(dá)式。

??? 右邊變成了一個(gè)表達(dá)式,是不是意味著我們剛才說(shuō)的右邊只能是一個(gè)值的規(guī)則不適用了呢?
不是! 記住了,少俠,賦值賦值,所以右邊必須得是一個(gè)值。
之所以表達(dá)式也可以放在右邊,是因?yàn)楸磉_(dá)式可以變成一個(gè)值,所以我們可以先解析它,獲取到一個(gè)值,然后放進(jìn)去:

“為什么可以在右邊放一個(gè)表達(dá)式呢?”
“因?yàn)楸磉_(dá)式可以變成一個(gè)值!”
“為什么表達(dá)式可以變成一個(gè)值呢?”
“因?yàn)榭梢宰兂芍档臇|西就是表達(dá)式!”
“為什么。。。”
“哪有那么多為什么!”
所以,少俠你可以在右邊放置任何表達(dá)式,但是,最終,它們都會(huì)轉(zhuǎn)成一個(gè)值。
不管這個(gè)值是數(shù)字,字符串,還是函數(shù),只要轉(zhuǎn)換出一個(gè)可用的值,就可以了。
Ok~ 再重復(fù)一遍,如果右邊是一個(gè)表達(dá)式,它會(huì)先轉(zhuǎn)換成一個(gè)值,而且,重點(diǎn)是它會(huì)到此為止!
“真啰嗦,這么基礎(chǔ)的東西,還說(shuō)這么大一堆!”
“是啊是啊,還重復(fù)說(shuō)!”
沒(méi)錯(cuò)! 為什么要重復(fù)說(shuō)這個(gè)基礎(chǔ)的東西呢?
因?yàn)樗鼤?huì)產(chǎn)生蝴蝶效應(yīng),
還記得上節(jié)最后提到的問(wèn)題嗎?
為什么 obj1.fn = () => { obj2.fn(); } 會(huì)在箭頭函數(shù)調(diào)用時(shí)再去查找 obj2.fn,而直接賦值 obj1.fn = obj2.fn 卻不在調(diào)用 obj1.fn 時(shí)再去查找 obj2 中的 fn 呢
也就是下面這樣的情況:

從上一節(jié)的內(nèi)容中,少俠你應(yīng)該知道,第一種方式的話(huà),屬于 early-bound,而第二種方式,屬于late-bound。
一個(gè)大的區(qū)別就是我們?cè)谶^(guò)后改變了 obj2.fn 的函數(shù)后,一個(gè)會(huì)更新,另一個(gè)不會(huì)。
第一種方式:

第二種方式:

造成這種差異的原因就是賦值規(guī)則導(dǎo)致的:
第一種賦值情況:

這里右邊是什么呢? 右邊是 obj2.fn
第二種賦值情況:

這里右邊是什么呢? 右邊是 () => obj2.fn();
重點(diǎn)來(lái)了! obj2.fn 是一個(gè)表達(dá)式! 而 () => obj2.fn() 是一個(gè)函數(shù)!
我們已經(jīng)提到過(guò),賦值的右邊必須是值,而 obj2.fn 是表達(dá)式,所以我們必須解析它,直到獲得一個(gè)值。

而另外一種情況呢?
() => obj2.fn() 是一個(gè)函數(shù),而函數(shù)本身就是一個(gè)值,所以我們不需要做任何操作!

我們這里并不會(huì)再去關(guān)心函數(shù)內(nèi)部 obj2.fn 是什么情況,因?yàn)楹瘮?shù)還沒(méi)有觸發(fā),而賦值的話(huà)由于外部箭頭函數(shù)已經(jīng)是一個(gè)值了,所以到這也就結(jié)束了。
所以,第一種情況下,賦值結(jié)束后,obj1.fn 和 obj2.fn 沒(méi)有任何關(guān)聯(lián)了,

每次調(diào)用 obj1.fn,會(huì)直接調(diào)用這個(gè)函數(shù)。
而第二種情況則會(huì)和 obj2.fn 有關(guān)聯(lián):

每次調(diào)用 obj1.fn 時(shí),進(jìn)入到箭頭函數(shù)內(nèi)部,都會(huì)重新查找一遍 obj2.fn,并調(diào)用它。
很神奇吧?
現(xiàn)在少俠你知道為什么obj1.fn = obj2.fn 會(huì)立刻查找 obj2.fn 的值了吧,因?yàn)?賦值操作右邊必須是值,而 obj2.fn 不是,所以會(huì)先解析它,直到獲取到一個(gè)可用的值。
而 obj1.fn = () => obj2.fn(); 由于右邊就是一個(gè)函數(shù),函數(shù)本身就是一個(gè)值了,所以會(huì)到此為止,并不會(huì)再去關(guān)心函數(shù)內(nèi)部什么情況。
造成這樣差距的,就是和一個(gè)小小的賦值運(yùn)算有關(guān)。
“有時(shí)候,讓你陷入麻煩的并不是你不知道的事,而是那些你自以為了解,但實(shí)際上卻是錯(cuò)誤的事?!R克吐溫”
直覺(jué)與規(guī)則,應(yīng)該相信哪一個(gè)?
這里另外一個(gè)有趣的地方就是函數(shù)必須是惰性的,這樣我們才可以利用一個(gè)中間的箭頭函數(shù)實(shí)現(xiàn) late-bound obj2.fn。
惰性的意思也就是說(shuō),函數(shù)內(nèi)部的事情,必須要在它被調(diào)用時(shí)候,才產(chǎn)生效果。
你不調(diào)用它的時(shí)候,就什么也不會(huì)發(fā)生。
即使它內(nèi)部可能很危險(xiǎn):

這個(gè)其實(shí)挺合理的,盡量只加載必要的內(nèi)容,在需要時(shí)候再去查找相關(guān)的內(nèi)容,肯定比每次一開(kāi)始就將所有內(nèi)容全部加載要好很多。
所以,就算你在函數(shù)內(nèi)部引用了一大堆變量,也只會(huì)在調(diào)用它時(shí)才開(kāi)始查找:

甚至你函數(shù)內(nèi)部引用了未定義的變量,只要你不觸發(fā)它,也不會(huì)報(bào)錯(cuò):

理所當(dāng)然的,既然是在函數(shù)調(diào)用時(shí)才開(kāi)始查找對(duì)應(yīng)的元素,那么如果元素中途發(fā)生了改變,也應(yīng)該以最后一次為準(zhǔn),對(duì)吧?

舉個(gè)更貼近現(xiàn)實(shí)的例子,

如果一個(gè)妹子和你只是普通朋友關(guān)系,直接親可能臉都要被打腫,但是如果先想辦法追到手,變成女朋友了,情況可能就不一樣了。
當(dāng)然,這里還是順便說(shuō)一下如果有普通朋友關(guān)系也可以親的妹子請(qǐng)聯(lián)系我!
“。。。???”
“一天都弄些什么亂七八糟的例子?。?!”
好了,現(xiàn)在我們回頭看的話(huà),下面這樣的情況少俠你應(yīng)該就很好理解了:

OK,現(xiàn)在,少俠你知道了賦值的規(guī)則,知道了函數(shù)是惰性的,知道了如果函數(shù)中引用了一個(gè)變量,在函數(shù)調(diào)用時(shí)才會(huì)去查找,也知道了應(yīng)該以這個(gè)變量最后調(diào)用時(shí)的值為準(zhǔn),balabala。。。
按照道理來(lái)說(shuō),少俠你應(yīng)該已經(jīng)能夠處理相關(guān)的問(wèn)題了,
但是~
少俠你的直覺(jué)有時(shí)候會(huì)欺騙你

這里調(diào)用兩次函數(shù)的結(jié)果是什么呢?
如果少俠你認(rèn)為是 0 和 1 的話(huà),就說(shuō)明在 JS 規(guī)則和你的直覺(jué)之間,你相信了后者。
正確答案是 2 2。
如果少俠你真的按照我們所說(shuō)的JS規(guī)則,一步一步分析的話(huà),結(jié)果應(yīng)該是下面這樣:

而認(rèn)為結(jié)果是0 和 1 的原因是少俠你的大腦忽略了 JS 世界中的規(guī)則,轉(zhuǎn)而采用了更快更輕松的直覺(jué)感受,你的直覺(jué)會(huì)發(fā)現(xiàn)每次遍歷時(shí) i 是 0 和 1,它會(huì)自然的認(rèn)為函數(shù)里的 i 每次也是 0 和 1。
這是你大腦第一反應(yīng)的規(guī)則:

但事實(shí)上,是函數(shù)里面的 i 和遍歷時(shí)的 i 沒(méi)有關(guān)系,因?yàn)楹瘮?shù)是惰性的,它里面的 i 要等到調(diào)用時(shí)才開(kāi)始查找。

跟隨大腦的想法
好了,經(jīng)過(guò)上面的內(nèi)容,少俠你應(yīng)該知道了規(guī)則和直覺(jué)有時(shí)候會(huì)產(chǎn)生沖突,
大腦的第一直覺(jué)不一定總是可靠。
不過(guò),
大腦雖然會(huì)犯錯(cuò),但是它也有很多好處,
比如如果不是它知道如何控制你用嘴巴吃飯,你可能會(huì)餓死!
另外一個(gè)好處就是它也喜歡觀察并總結(jié)發(fā)現(xiàn)的事物規(guī)律,
大腦經(jīng)常也會(huì)很好奇,可能會(huì)產(chǎn)生一些奇怪的腦洞,有時(shí)候,跟隨大腦的想法,也能夠幫助你發(fā)現(xiàn)新大陸。
比如,我們上面的函數(shù)都沒(méi)有使用到 this,
如果你碰巧又才學(xué)習(xí)了 this,
你的大腦可能會(huì)想,如果將 this 考慮進(jìn)來(lái),會(huì)發(fā)生什么事呢?
這里我們結(jié)合上一節(jié)的內(nèi)容看看,
第一種情況:

第二種情況:

很熟悉的內(nèi)容,因?yàn)檫@就是我們上一次提到的 mixin 和 forward 的情況。
由于上一節(jié)已經(jīng)詳細(xì)說(shuō)過(guò)這些內(nèi)容了,所以這里就簡(jiǎn)單說(shuō)下結(jié)果,
第一種情況調(diào)用 obj1.fn 會(huì)打印出 obj1 中的 name,'天辰dreamer'。
而第二種情況調(diào)用 obj1.fn 會(huì)打印 obj2 中的 name,也就是 '烏云dreamer',
而且由于我們的箭頭函數(shù)是惰性的原因,第二種情況可以在中途改變 obj2.fn 的內(nèi)容,obj1.fn 會(huì)自動(dòng)更新。

還記得我們上一次的表格嗎?
| 組合方式 | bound 類(lèi)型 | 方法中的作用對(duì)象 | 數(shù)據(jù)是否獨(dú)立 |
|---|---|---|---|
| mixin | early-bound | 對(duì)象本身 | 是,每個(gè)對(duì)象的操作不會(huì)影響其他 mixin 對(duì)象 |
| forward | late-bound | 用于組合的對(duì)象 | 否,用于所有對(duì)象會(huì)共享 forward 進(jìn)來(lái)的對(duì)象數(shù)據(jù),所以會(huì)互相影響 |
如果少俠你仔細(xì)觀察的話(huà),你可能會(huì)想,
obj1.fn = obj2.fn 中,它是 early-bound,同時(shí)方法中的 this 作用于 obj1。
而 obj1.fn = () => { obj2.fn() } 中,它是 late-bound, 同時(shí)方法中的 this 會(huì)指向 obj2。
是不是好像缺了兩種情況?
比如能不能實(shí)現(xiàn) early-bound,而 this 作用于 obj2,
或者實(shí)現(xiàn) late-bound, this 卻作用于 obj1 上呢?

哈哈哈哈哈哈~
沒(méi)想到吧!又繞回來(lái)了!
劇情居然突然變得陡峭了起來(lái),基礎(chǔ)不穩(wěn)的少俠有沒(méi)有躲在一旁瑟瑟發(fā)抖?是不是有點(diǎn)措手不及?
“。。。。。。。。。?!?/p>

好了,嚴(yán)肅臉!
不是故意花里胡哨,這些內(nèi)容是我認(rèn)為少俠你應(yīng)該理解的,理解它們對(duì)你熟練掌握J(rèn)S很有幫助,同時(shí)能避免很多日常坑,也對(duì)我們接下來(lái)要遇見(jiàn)的 prototype 有很大幫助。
如果你覺(jué)得沒(méi)用的話(huà),我不要你覺(jué)得,我要我覺(jué)得!
那么,最后兩種情況到底能不能實(shí)現(xiàn)呢?
“當(dāng)然可以了,不可以的話(huà),天辰你提它們干嘛?”
“我隨便說(shuō)一說(shuō)不行嘛?”
“騙誰(shuí)呢,肯定可以。”
“那我這里說(shuō)它不可以?!?/p>
“不可以算了,反正我們也沒(méi)興趣?!?/p>
“少俠你怎么能說(shuō)放棄就放棄呢? 再試一試。”
“不試!”
“我糾正一下剛說(shuō)過(guò)的話(huà),是可以實(shí)現(xiàn)的。”
“沒(méi)興趣了?!?/p>
“不會(huì)很難的?!?/p>
“就不試!”
“。。。。。。”
天辰突然和自己內(nèi)心幻想出來(lái)的角色吵了起來(lái),一時(shí)生氣直接跑走了,臨走前扔下了一張皺巴巴的小紙條。。。
1、函數(shù)是惰性的,所有放在函數(shù)內(nèi)部的變量,都會(huì)在該函數(shù)調(diào)用時(shí)才開(kāi)始查找,所以 early-bound 和 late-bound 的關(guān)鍵區(qū)別可能是元素放置在函數(shù)內(nèi)外的不同。

2、你可以通過(guò)將普通函數(shù)放置在不同對(duì)象上調(diào)用來(lái)改變其中的 this 指向,你需要 this 指向 a, 你就放在 a 上調(diào)用,你需要 this 指向 b, 你就放在 b 上調(diào)用。

3、重新回顧一下我們最開(kāi)始提到的很基礎(chǔ)的規(guī)則可能會(huì)有幫助。
4、少俠,江湖路遠(yuǎn),有緣再見(jiàn)~
一些你可能關(guān)心的問(wèn)題
1、感覺(jué)更新有點(diǎn)慢,天辰你能不能更新快一點(diǎn)?
不好弄,要有靈感了才能寫(xiě),而且如果我自己讀著都比較尷尬的話(huà)就不好意思發(fā)出來(lái),得反復(fù)改很多次才行。。。
2、說(shuō)好的藍(lán)胖dreamer圖片呢?
好了,這就是可愛(ài)又聽(tīng)話(huà)的藍(lán)胖dreamer了~

你可能會(huì)以為藍(lán)胖會(huì)是只英短貓,但是我叫它藍(lán)胖的原因只是因?yàn)樗劬κ撬{(lán)色的很好看,然后它長(zhǎng)得又比較胖。。。
3、這次的文章有點(diǎn)奇怪,感覺(jué)好像你說(shuō)了一大堆,又感覺(jué)好像什么都沒(méi)說(shuō)。
很好,說(shuō)明我的文章已經(jīng)超出了單純的文章本身!已經(jīng)有點(diǎn)道的感覺(jué)了,只可意會(huì)不可言傳~
3、好吧好吧,那么下一次會(huì)有 prototype 嗎?!
為什么要急著遇見(jiàn)什么呢?少俠。
說(shuō)不定當(dāng)我們真正遇見(jiàn)了 prototype 之后,你反而會(huì)開(kāi)始懷念起現(xiàn)在的時(shí)刻呢~
4、文章結(jié)尾是不是太倉(cāng)促隨意了?
這還叫倉(cāng)促隨意?少俠你應(yīng)該是沒(méi)有看過(guò)更倉(cāng)促的結(jié)尾方式,比如:
聲明:本文僅限于瀟灑有趣又很酷的天辰dreamer裝逼使用,轉(zhuǎn)載請(qǐng)注明原作者和出處,商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系我(如果真有的話(huà))。。。
