JavaScript中的立即執行函數

NO IMAGE

原文鏈接

通常我們聲明一個函數有以下幾種方式:

// 聲明函數f1
function f1() {
console.log("f1");
}
// 通過()來調用此函數
f1();
//一個匿名函數的函數表達式,被賦值給變量f2:
var f2 = function() {
console.log("f2");
}
//通過()來調用此函數
f2();
//一個命名為f3的函數的函數表達式(這裡的函數名可以隨意命名,可以不必和變量f3重名),被賦值給變量f3:
var f3 = function f3() {
console.log("f3");
}
//通過()來調用此函數
f3();

如果你看過一些自定義控件的話你會發現他們大多數都是沿用這種寫法:

(function() {

// 這裡開始寫功能需求
})();

這是我們常說的立即執行函數(IIFE),顧名思義,也就是說這個函數是立即執行函數體的,不需要你額外去主動的去調用,一般情況下我們只對匿名函數使用IIFE,這麼做有兩個目的:
> 一是不必為函數命名,避免了汙染全局變量
> 二是IIFE內部形成了一個單獨的作用域,可以封裝一些外部無法讀取的私有變量。
如果看到這兩句話無法理解,那麼先從IIFE的運行原理說起。
因為IIFE通常用於匿名函數,這裡就用簡單的匿名函數作為栗子:
```javascript
var f = function(){
console.log("f");
}
f();

我們發現這裡f只是這個匿名函數的一個引用變量,那麼既然f()能夠調用這個函數,我把f替換成函數本身可以麼:

function(){
console.log("f");    
}();

運行之後得到如下結果:

Uncaught SyntaxError: Unexpected token (

產生這個錯誤的原因是,Javascript引擎看到function關鍵字之後,認為後面跟的是函數聲明語句,不應該以圓括號結尾。解決方法就是讓引擎知道,圓括號前面的部分不是函數定義語句,而是一個表達式,可以對此進行運算,這裡區分一下函數聲明和函數表達式:

1、函數聲明(即我們通常使用function x(){}來聲明一個函數)
function myFunction () { /* logic here */ }
2、函數表達式(類似以這種的形式)
var myFunction = function () { /* logic here */ };
var myObj = {
myFunction: function () { /* logic here */ }
};

小學我們就學過用()括起來的表達式會先執行,就像下面這樣:

1+(2+3) //這裡先運行小括號裡面的內容沒有意見撒

其實在javascript中小括號也有相似的作用,Javascript引擎看到function關鍵字會認為是函數聲明語句,那麼如果Javascript引擎優先看到小括號會怎麼樣:

//用小括號把函數包裹起來
(function(){
console.log("f");    
})();

函數成功執行了:

f //控制檯輸出

這種情況下Javascript引擎就會認為這是一個表達式,而不是函數聲明,當然要讓Javascript引擎認為這是一個表達式的方法還有很多:

!function(){}();
+function(){}();
-function(){}();
~function(){}();
new function(){ /* code */ }
new function(){ /* code */ }() // 只有傳遞參數時,才需要最後那個圓括號。
……

回到前面的問題,為什麼說IIFE這種形式避免了汙染全局變量,如果你見過別人寫的jquery插件,裡面通常會有類似這樣的代碼:

(function($){

//插件實現代碼
})(jQuery);
``
這裡的
jquery其實是該匿名函數的參數,聯想一下我們調用匿名函數時候是用f()那麼匿名帶參數的就是f(args)對吧,這裡把jquery作為參數傳入該函數,那麼在函數內部使用形參$的時候就不會影響到外部環境,因為有些插件也會用到$`這個限定符,你在這個函數內部可以隨意折騰。

以上,在此過程中參考了以下兩篇文章:
javascript立即執行某個函數:插件中function(){}()再思考
JavaScript中的立即執行函數

相關文章

PHP中類和文件的代碼註釋規範

Laravel+vue之環境部署

Laravel定製500錯誤頁

瀏覽器運行環境知識點(不定期更新)