JavaScript中的函數作用域的存在就是為了把變數和函數「隱藏」起來
#符合我們的最小特權原則
同時它的另一個好處是可以避免同名標識符的衝突
今天主要來談談這個立即執行函數
在此之前的複習一下匿名函數與具名函數
#無論是匿名還是具名,都是針對函數表達式來說的
函數宣告那就必須得有名字了,否則會報錯的
function foo(){ //函数声明 //...}
這裡我解釋一個彩蛋,可能大家看我寫文章的時候範例程式碼總是喜歡用一些
fn、func、demo、foo、bar、foobar之類的字
fn、func就是function「函數」的縮寫
demo就是單字demonstration「範例」的縮寫
foo、bar、foobar我們常常能夠在技術書籍還有電腦文獻中看到
foo是fu的變體,fuck-up縮寫,意思是「一團糟」
bar是“beyond all recognition”,意思是“超越認知”,通俗說“識別不了,一塌糊塗”
就是一些佔位詞,相當於我們的小明小紅、甲乙丙丁、張三李四…
函數表達式是可以有名字,也可以沒有名字的
var foo = function(){...}; console.log(foo.name); //foo var bar = function foobar(){...};//不要这么写 console.log(bar.name); //foobar
可以看到第二種寫法只是單純地改變了函數的name屬性
除此之外百無一用,我們不要這麼寫
除此之外我們最常見的用法就是函數表達式作為回呼參數了
比如說在定時器中
setTimeout(function(){ //...},1000);
這裡我寫了匿名函數表達式
它用起來簡單粗暴
但有幾個缺點
追蹤堆疊中沒函數名,調試困難
如果需要引用自身,只能用arguments.callee(ES5嚴格模式停用)
降低了函數可讀性、可理解性
我們在解除事件綁定時,也需要函數名稱(如果不是用onclick等等直接綁定的話)
所以
給函數表達式一個名字是一個最佳實踐,是一個好習慣
setTimeout(function timerHandler(){ //...},1000);
立即執行函數,我習慣這麼叫
也有叫自執行函數、自動執行函數什麼的
說的更標準一些
立即執行函數表達式
注意我的用詞,是函數表達式
它不是什麼語法
而是大家用著用著發現還能這麼用
於是就流傳開來,直到現在
顧名思義,就是執行流運行到這個函數就立刻執行了
社區給它規定了術語:IIFE(Immediately Invoked Function Expression)
我們常用的用法是:
(function(){ //...}());
(function(){ //...})();
我們用IIFE的時候一般都是使用一個匿名函數來表達式
當然你加上名字也不錯,同時擁有了具名函數表達式的優點
兩種用法完全等價,使用哪種由你決定
但我更願意把括號寫在外面,感覺看著比較舒服
而且看到很多大神也跟我一樣
稍微進階的用法就是在立即執行函數中傳遞參數
比如說我們常見的傳遞window
var a = '全局'; (function IIFE(global){ var a = '局部'; console.log(a);// "局部" console.log(global.a);// "全局"})(window);
傳window有什麼好處呢?
從我們作用域的角度分析
(可以看看我寫的作用域->傳送門)
全域物件的參考快取到了局部環境
這樣我們可以更快的存取到全域對象,不用再跳到頂級作用域查找
這點小優化不是重點
重點的壓縮程式碼的時候可以進行最佳化
也許上面的程式碼壓縮工具可以壓縮成這樣
var a = '全局'; (function IIFE(g){ var a = '局部'; console.log(a);// "局部" console.log(g.a);// "全局"})(window);
當程式碼非常大的時候,可不要小看這優化
#IIFE還有一種變式,你一定看過
(function IIFE(demo){ demo(window);})(function demo(global){ //... });
這種把要運行的函數放進參數的模式看起來很麻煩
但卻被廣泛使用,jQuery等框架整體架構也和這個很像
如果看習慣了,就會感覺它比我們傳統的使用方法更容易理解
整體的函數表達式定義在IIFE第二部分,作為參數傳遞進IIFE第一部分
然後調用了這個函數,並且把window作為參數傳入
立即執行函數為什麼能夠自動執行?
(function(){ //...})();
為什麼function(){}()
這樣寫不可以
因為這是函數聲明,函數宣告是不可以執行的
只有表達式才能夠執行
var demo = function(){ console.log(1);// 1 return 123; }(); console.log(demo);// 123
這就是一個表達式,所以可以被執行
demo得到的是函數的回傳值
既然表達式可以被執行,那麼以下方式都可以被立即執行
+function(){ console.log(1);// 1}(); -function(){ console.log(2);// 2}(); !function(){ console.log(3);// 3}() ,function(){ console.log(4);// 4}();
可以看出甚至是逗號,都可以它們變成函數表達式,然後立刻執行
不過我們千萬不要這麼寫
如果函數有回傳值的話,可能會產生意想不到的副作用
且可讀性也不好
函數宣告必須有名字
具名函數表達式是一個最佳實踐
立即執行函數表達式用法:(function(){}());
(function(){})();
#立即執行函數傳遞window參數最佳化在作用域鏈中尋找window速度,有利於壓縮程式碼
只有表達式才能夠被執行
以上就是JavaScript匿名、具名函數與立即執行函數IIFE詳解 的內容,更相關內容請關注PHP中文網(www.php.cn)!