少俠, JS基礎(chǔ)知識(shí)產(chǎn)生的蝴蝶效應(yīng)能有多大?~

image

少俠們好~

又是一段時(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)的比較好。

上一篇鏈接:

少俠,prototype前傳,了解一下?


回到起點(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ù)字,布爾值等等。

image

除此之外,還有一些稍微復(fù)雜一些的元素,

比如對(duì)象,數(shù)組,以及函數(shù)等等。

image

知道了值之后,另外一個(gè)和它息息相關(guān)的內(nèi)容是表達(dá)式。

什么是表達(dá)式呢? 簡(jiǎn)單來(lái)說(shuō),能夠直接轉(zhuǎn)化成值的東西,就叫做表達(dá)式。

記住了,少俠,表達(dá)式可以直接轉(zhuǎn)化變成一個(gè)值,但是它并不是一個(gè)值。

image

這次的內(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è)變量賦值:

image

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

image

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

image

那么問(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)。

image

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

image

你可以放的只有值:

image

But! 生活總會(huì)有意外情況~

有時(shí)候,右邊會(huì)是一個(gè)表達(dá)式。

image

??? 右邊變成了一個(gè)表達(dá)式,是不是意味著我們剛才說(shuō)的右邊只能是一個(gè)值的規(guī)則不適用了呢?

不是! 記住了,少俠,賦值賦值,所以右邊必須得是一個(gè)值。

之所以表達(dá)式也可以放在右邊,是因?yàn)楸磉_(dá)式可以變成一個(gè)值,所以我們可以先解析它,獲取到一個(gè)值,然后放進(jìn)去:

image

“為什么可以在右邊放一個(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 呢

也就是下面這樣的情況:

image

從上一節(jié)的內(nèi)容中,少俠你應(yīng)該知道,第一種方式的話(huà),屬于 early-bound,而第二種方式,屬于late-bound。

一個(gè)大的區(qū)別就是我們?cè)谶^(guò)后改變了 obj2.fn 的函數(shù)后,一個(gè)會(huì)更新,另一個(gè)不會(huì)。

第一種方式:

image

第二種方式:

image

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

第一種賦值情況:

image

這里右邊是什么呢? 右邊是 obj2.fn

第二種賦值情況:

image

這里右邊是什么呢? 右邊是 () => obj2.fn();

重點(diǎn)來(lái)了! obj2.fn 是一個(gè)表達(dá)式! 而 () => obj2.fn() 是一個(gè)函數(shù)!

我們已經(jīng)提到過(guò),賦值的右邊必須是值,而 obj2.fn 是表達(dá)式,所以我們必須解析它,直到獲得一個(gè)值。

image

而另外一種情況呢?

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

image

我們這里并不會(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)了,

image

每次調(diào)用 obj1.fn,會(huì)直接調(diào)用這個(gè)函數(shù)。

而第二種情況則會(huì)和 obj2.fn 有關(guān)聯(lián):

image

每次調(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):

image

這個(gè)其實(shí)挺合理的,盡量只加載必要的內(nèi)容,在需要時(shí)候再去查找相關(guān)的內(nèi)容,肯定比每次一開(kāi)始就將所有內(nèi)容全部加載要好很多。

所以,就算你在函數(shù)內(nèi)部引用了一大堆變量,也只會(huì)在調(diào)用它時(shí)才開(kāi)始查找:

image

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

image

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

image

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

image

如果一個(gè)妹子和你只是普通朋友關(guān)系,直接親可能臉都要被打腫,但是如果先想辦法追到手,變成女朋友了,情況可能就不一樣了。

當(dāng)然,這里還是順便說(shuō)一下如果有普通朋友關(guān)系也可以親的妹子請(qǐng)聯(lián)系我!

“。。。???”

“一天都弄些什么亂七八糟的例子?。?!”

好了,現(xiàn)在我們回頭看的話(huà),下面這樣的情況少俠你應(yīng)該就很好理解了:

image

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ì)欺騙你

image

這里調(diào)用兩次函數(shù)的結(jié)果是什么呢?

如果少俠你認(rèn)為是 0 和 1 的話(huà),就說(shuō)明在 JS 規(guī)則和你的直覺(jué)之間,你相信了后者。

正確答案是 2 2。

如果少俠你真的按照我們所說(shuō)的JS規(guī)則,一步一步分析的話(huà),結(jié)果應(yīng)該是下面這樣:

image

而認(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ī)則:

image

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

image

跟隨大腦的想法

好了,經(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)容看看,

第一種情況:

image

第二種情況:

image

很熟悉的內(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)更新。

image

還記得我們上一次的表格嗎?

組合方式 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 上呢?

image

哈哈哈哈哈哈~

沒(méi)想到吧!又繞回來(lái)了!

劇情居然突然變得陡峭了起來(lái),基礎(chǔ)不穩(wěn)的少俠有沒(méi)有躲在一旁瑟瑟發(fā)抖?是不是有點(diǎn)措手不及?

“。。。。。。。。。?!?/p>

image

好了,嚴(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)外的不同。

image

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

image

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了~

image

你可能會(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à))。。。

image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容