JS 中 IIFE 與分號的最酷寫法

IIFE 是在 JS 中為了彌補沒有 block scope 而出現的寫法。 一般人習慣使用括號做為前置, 但其實括號出現在行首䆟易被 ASI 誤判為函數呼叫,使用上最佳寫法應為 !function(){}()void function(){}()

函數表達式

JS 中存在函數表達式 (expression) 與函數宣告,兩者語法很不幸的相同。 當函數表達式置於行首時, (其實應該說是一個陳述 (statement) 的開頭, 不一定不能是行首。) 就會被解釋為函數宣告。

所以使用 iife 時,唯一要注意就是 不要把 iife 放在句首即可; 其它你愛怎麼宣告,就怎麼宣告。

function foo() {} // declaretion
(function foo() {}) // expression, value is function.

!function bar() {}()
// iife, value is true,
// because function return undefined,
// !undefined == true

分號自動插入判斷

但身為懶惰的程式設計師, 當然可以不寫分號 ; 況且 feature 就是拿來用的, 不然 JS 幹麻設計分號自動插入的功能? 所以就簡單研究一下怎麼樣不寫分號會造成問題。

js 在句尾會自動判斷 statement 結尾, 只要 可能還沒結束 就會被當成沒結束, 就不會插入分號。

括號呼叫函數

當下一行以 ( 開頭,會被當成函數呼叫。

doc = createDocument(document)
(a+b) / c

因為 doc = createDocument(document) 也是一個表達式,返回 doc。 所以 doc 就會被當成函數以參數 a+b 呼叫, 然後一般就會丟出一個 Type error, 因為 doc 一般不會是函數。

(doc = createDocument(document))(a+b) / c

中括號存取陣列

當下一行以 [ 開頭,會被當成陣列, 所以也不要用 [ 開頭

doc = createDocument(document)
[1,2,3].forEach(doc.showIndex)

這點 js 真得有點笨, [1,2,3] 怎麼看都是陣列字面量, 但 JS 就會當成存取 doc 的屬性, 然後丟出語法錯誤,因為存取屬性不能有逗號。 (但實際試過,好像會只存取最後一個,不會丟語法錯誤。) 或因為 doc 返回了 undefined 或 null 丟 type error 或 reference error。

standerJS 的建議是不要把陣列字面量擺行首, 看要先前置分號或先賦值。

statement;
[1,2,3].forEach(doc.showIndex)
// not good.

;[1,2,3].forEach(doc.showIndex)
// good.

var list = [1,2,3]
list.forEach(doc.showIndex)
// better

一元算符

有沒有發現,我們用來防止誤認函數表達式的都是一元算符? 但有些一元算符因為也可以被當二元算符,而容易出錯。 像 + 可以是把數字加一個正號, (也就是什麼也不做。)或是把兩個數相加。 如果有上一個 statement,就會加在一起。 而括號可以是單純一元算符,(對內求值。) 或是將內部做為前一個表達式的參數呼叫函數。

+(-3) // expression, return -3.

var i = 1
+(-3) // ops, i = -2 now.

所以我們需要一個不會被當成二元算符的一元算符, 我的名單有 !~void! 很好理解,就是 bool 反轉, 僅次於 (function(){})() 的寫法就是 !function(){}() 。 而 ~ 是 bit 級 not 算符, 至於它對函數的運算結果,反正不是我們關心的。

最強寫法

最後一個 void 是我認為最強的寫法。 void 是一個較少人知道的算符, 她接受任何參數,然後返回 undefined。 所以你可以寫 void function(){}() , 是不是有 C 的感覺?是不是很帥!

因為 undefined 不是字面量, 她是一個 全域變數 , 在瀏覽器中是掛在 window 下面。 你可以在除了全域外的任何 scope 宣告 var undefined = true , 然後你就看不到 undefined 了ㄎㄎ

所以才有了 void 這個算符, 不管你有沒有對 undefined 動手腳, 不管你被包了幾層 scope, 只要對 void 隨便丟一個參數,都會返回 undefined。 一般的寫法是 void 0 ,但其實右邊放什麼都沒差。