整理這些技術筆記真的很花時間,如果你願意 關閉 Adblock 支持我,我會把這份感謝轉換成更多「踩坑轉避坑」的內容給你!ヽ(・∀・)ノ
關於在 Vue 的 Single-File Components 上使用 HOF 分析
前言
最近朋友私訊問了我一個 Vue 有趣的地方,是關於它嘗試在 Vue 的 Single-File Components 上使用 Higher-Order Function(HOF)結果卻發生一個很有趣的雷點,所以就來寫一篇文章來分析一下這個問題。
問題程式碼
首先這邊先提供範例程式碼
1 | |
如果覺得太長也可以看線上版:Vue SFC Playground
這邊我們透過操作可以發現 click1 按鈕是無效的,但是 click2 跟 click3 點了卻正常運作,而我們可以看到 handleActiveClick 採用的方式是 HOF 的方式,而 handleActiveClick2 則是一般的函式,那麼這個問題到底是什麼呢?
所以接下來就來準備分析一下這個問題。
分析問題
首先這個問題是發生在 Vue 的 Single-File Components 上,但是我們又不可能花時間去看 Vue 的原始碼,所以我們可以先透過簡單的方式來分析一下這個問題。
首先 Vue SFC Playground 上方可以看編譯後的結果,你可以點一下「JS」來看一下編譯後的結果,這邊我們可以看到編譯後結果如下
1 | |
那麼很複雜對吧?不用擔心,我們只需要看到底下這幾段地方就好
1 | |
首先直接看 render 的部分,可以看到會回傳兩個東西,分別是 _openBlock 跟 _createElementBlock,這邊只需要注意 _createElementBlock 的部分,_createElementBlock 的參數分別有三個,第一個是 Fragment,第二個是 null,第三個是一個陣列,而我們只需要注意第三個參數,也就是陣列的部分
那麼我們這邊是 <button type="button" @click="handleActiveClick('click1')">click 1</button> 無法正常運作,因此就可以看這一段
1 | |
_createElementVNode 基本上就是新增一個虛擬 DOM 元素的函式,這邊我們不用太深入,只需要專注於 onClick 這個屬性就好,這邊可以看到 onClick 的值是 _cache[0] || (_cache[0] = $event => ($setup.handleActiveClick('click1')))。
這邊可能稍微有一點複雜,首先這邊有一個 || 運算子,在 JavaScript 中當前者是 True 的時候就會回傳前者,若沒有就回傳後者,所以如果 _cache[0] 有值的時候就回傳 _cache[0],若沒有值就回傳 (_cache[0] = $event => ($setup.handleActiveClick('click1'))),但是這邊有一個重點也就是裡面有一個 () 函示呼叫的運算子,因此會優先執行 (_cache[0] = $event => ($setup.handleActiveClick('click1'))) 這一段程式碼,因此 (_cache[0] = $event => ($setup.handleActiveClick('click1'))) 會先變成以下
1 | |
接著因為裡面還有一個 () 函示呼叫的運算子,因此會先執行 $setup.handleActiveClick('click1'),但是這邊要注意前面我們的 handleActiveClick 是這樣寫
1 | |
因此套用過來時,完整版會變成以下
1 | |
所以完整版就變成了這樣
1 | |
那麼這也是為什麼當我們點擊第一個按鈕時會沒有任何反應的原因,因為其實回傳賦予給 onClick 的只是一個單純沒任何行為的函式,如果這樣不好讀的話,你可以看看以下是否比較好理解
1 | |
我們都知道這是一個類似閉包(Closure)的寫法,因此通常我們在寫閉包時,都會需要將函式回傳並儲存到一個變數內,如以下範例
1 | |
而這也就是為什麼第一個按鈕會失效的原因了,因為我們只是將函式回傳給 onClick,但是並沒有執行。
那為什麼第二個按鈕可以正常呢?因為我們在第二個按鈕的 onClick 是這樣寫的
1 | |
我們可以看到呼叫了 handleActiveClick 並且執行了函式,因此第二個按鈕回傳的就是以下
1 | |
第三個呢?為什麼正常運作呢?因為我們只是單純的傳入一個函式,因此不會有閉包的問題,因此第三個按鈕的 onClick 會是以下
1 | |
最後這邊也分享一下四種 @click 寫法
1 | |
而他們編譯出來會是以下
1 | |
透過以上分析,你應該就大概知道為什麼第一個按鈕會失效了吧~
那麼這邊應該也會有人好奇 React 的部分,這邊我就額外補上 React 編譯後的程式碼
1 | |
這樣就可以大概知道 Vue 跟 React 實作上是有一定差異的。
整理這些技術筆記真的很花時間,如果你願意 關閉 Adblock 支持我,我會把這份感謝轉換成更多「踩坑轉避坑」的內容給你!ヽ(・∀・)ノ