1. 程式人生 > >JavaScript/JQuery自執行函式

JavaScript/JQuery自執行函式

自執行函式

JavaScript中任何庫與框架設計的第一個要點就是解決名稱空間與變數汙染的問題。jQuery就是利用了JavaScript函式作用域的特性,採用自執行函式包裹了自身的方法來解決這個問題。從jQuery不同的版本中可以看出它的自執行函式有如下兩種寫法:

    // 寫法一
    (function(window, factory) {
        factory(window)
    }(this, function() {
        return function() {
           //jQuery的呼叫
        }
    }));

    // 寫法二
(function(window, undefined) { var jQuery = function() {} // ... window.jQuery = window.$ = jQuery; })(window);

為了更好地理解它的做法,需要先強化一些函式的基本概念。

函式宣告、函式表示式與匿名函式

  • 函式宣告:使用function關鍵字宣告一個函式,再指定一個函式名,叫函式宣告。
    function funcName() {
        ...
    }
  • 函式表示式與匿名函式:未給函式命名,但最後將匿名函式賦予一個變數,叫函式表示式,否則就是匿名函式。因此匿名函式也屬於函式表示式
    var funcName = function() {
        ...
    }
  • 區別:關於函式宣告,它的一個重要特徵就是函式宣告提升,意思是在執行程式碼之前會先讀取函式宣告。這就意味著可以把函式宣告放在呼叫它的語句後面;而函式表示式在呼叫之前需要賦值。
    sayHi(); // It's OK
    function sayHi() {
        alert("Hi!");
    }

    sayHi(); // undefined!
    var sayHi = function() {
        alert("Hi!");
    }

函式表示式 + ()

很重要的一點是:函式表示式後面通過加括號,能夠立即呼叫該函式,而函式宣告不可以!

    function sayHi() {
        alert("Hi!");
    }() // illegal

    var sayHi = function() {
        alert("Hi!");
    }() // legal

需要注意的是,匿名函式雖然屬於函式表示式,但是在匿名函式後面加括號來直接呼叫是行不通的,因為JavaScript直譯器將開頭的function關鍵字當做函式宣告,會報錯:需要一個函式名

    function() {
        alert("Hi!");
    }() // illegal : function name expected

如何正確告訴JavaScript直譯器這是一個匿名函式,而不是一個函式宣告

由於匿名函式這個會被誤解的存在,因此需要想辦法正確告訴JavaScript直譯器這是一個匿名函式,即函式表示式,而不是一個函式宣告。而這樣的方法就是:在function前面加上+-=()等運算子,而這之中最安全的做法便是加()

    !function() {
        alert("Hi!");
    }(); // legal

    +function() {
        alert("Hi!");
    }(); // legal

    -function() {
        alert("Hi!");
    }(); // legal

    var sayHi = function() {
        alert("Hi!");
    }(); // legal

    (function() {
        alert("Hi!");
    })(); // legal, notice

    (function() {
        alert("Hi!");
    }()); // legal, notice

加別的運算子也許會引起不必要的麻煩,而加括號是很好的做法。注意上面最後的2個做法,代表了(function() {})();(function() {}());
回頭來看jQuery的兩種寫法:

    // 寫法一
    (function(window, factory) {
        factory(window)
    }(this, function() {
        return function() {
           //jQuery的呼叫
        }
    })); // 其實寫法一可以看成是(function() {}());

    // 寫法二
    (function(window, undefined) {
        var jQuery = function() {}
        // ...
        window.jQuery = window.$ = jQuery;
    })(window); // 而寫法而可以看成是(function() {})();

所以這兩種寫法在自執行上本質是一樣的。

採用這種寫法的意義

JavaScript中沒有私有作用域的概念,如果在多人開發的專案上,你在全域性或區域性作用域中聲明瞭一些變數,可能會被其他人不小心用同名的變數給覆蓋掉。根據JavaScript函式作用域鏈的特性,可以使用這種技術模仿一個私有作用域,把匿名函式作為一個“容器”,內部可以訪問外部的變數,而外部環境不能訪問內部。從而達到保護jQuery內部變數的作用。