一般咱們聲明一個函數有如下幾種方式:javascript
// 聲明函數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();複製代碼
若是你看過一些自定義控件的話你會發現他們大多數都是沿用這種寫法:html
(function() {複製代碼
// 這裏開始寫功能需求
})(); java
這是咱們常說的當即執行函數(IIFE),顧名思義,也就是說這個函數是當即執行函數體的,不須要你額外去主動的去調用,通常狀況下咱們只對匿名函數使用IIFE,這麼作有兩個目的:
> 一是沒必要爲函數命名,避免了污染全局變量
> 二是IIFE內部造成了一個單獨的做用域,能夠封裝一些外部沒法讀取的私有變量。
若是看到這兩句話沒法理解,那麼先從IIFE的運行原理提及。
由於IIFE一般用於匿名函數,這裏就用簡單的匿名函數做爲栗子:
```javascript
var f = function(){
console.log("f");
}
f();複製代碼
咱們發現這裏f
只是這個匿名函數的一個引用變量,那麼既然f()
可以調用這個函數,我把f
替換成函數自己能夠麼:jquery
function(){
console.log("f");
}();複製代碼
運行以後獲得以下結果:segmentfault
Uncaught SyntaxError: Unexpected token (複製代碼
產生這個錯誤的緣由是,Javascript引擎看到function關鍵字以後,認爲後面跟的是函數聲明語句,不該該以圓括號結尾。解決方法就是讓引擎知道,圓括號前面的部分不是函數定義語句,而是一個表達式,能夠對此進行運算,這裏區分一下函數聲明和函數表達式:bash
1、函數聲明(即咱們一般使用function x(){}來聲明一個函數)
function myFunction () { /* logic here */ }
2、函數表達式(相似以這種的形式)
var myFunction = function () { /* logic here */ };
var myObj = {
myFunction: function () { /* logic here */ }
};複製代碼
小學咱們就學過用()
括起來的表達式會先執行,就像下面這樣:jquery插件
1+(2+3) //這裏先運行小括號裏面的內容沒有意見撒複製代碼
其實在javascript
中小括號也有類似的做用,Javascript引擎看到function關鍵字會認爲是函數聲明語句,那麼若是Javascript引擎優先看到小括號會怎麼樣:函數
//用小括號把函數包裹起來
(function(){
console.log("f");
})();複製代碼
函數成功執行了:ui
f //控制檯輸出複製代碼
這種狀況下Javascript引擎就會認爲這是一個表達式,而不是函數聲明,固然要讓Javascript引擎認爲這是一個表達式的方法還有不少:spa
!function(){}();
+function(){}();
-function(){}();
~function(){}();
new function(){ /* code */ }
new function(){ /* code */ }() // 只有傳遞參數時,才須要最後那個圓括號。
……複製代碼
回到前面的問題,爲何說IIFE這種形式避免了污染全局變量,若是你見過別人寫的jquery插件,裏面一般會有相似這樣的代碼:
(function($){複製代碼
//插件實現代碼
})(jQuery);`` 這裏的
jquery實際上是該匿名函數的參數,聯想一下咱們調用匿名函數時候是用
f()那麼匿名帶參數的就是
f(args)對吧,這裏把jquery做爲參數傳入該函數,那麼在函數內部使用形參
$的時候就不會影響到外部環境,由於有些插件也會用到
$`這個限定符,你在這個函數內部能夠隨意折騰。
以上,在此過程當中參考瞭如下兩篇文章:
javascript當即執行某個函數:插件中function(){}()再思考
JavaScript中的當即執行函數