匿名函式

定義匿名函式

定義函式時,通常會給它命名,然後使用該名稱呼叫它,如下所示:

foo();

function foo(){
    // ...
}

當你以這種方式定義函式時,Javascript 執行時將你的函式儲存在記憶體中,然後使用你為其指定的名稱建立對該函式的引用。然後可以在當前範圍內訪問該名稱。這可以是建立函式的一種非常方便的方法,但 Javascript 不要求你為函式指定名稱。以下也是完全合法的:

function() {
    // ...
}

如果定義的函式沒有名稱,則稱為匿名函式。該函式儲存在記憶體中,但執行時不會自動為你建立對它的引用。乍一看,似乎這樣的東西似乎毫無用處,但有幾種情況下匿名函式非常方便。

為變數分配匿名函式

匿名函式的一個非常常見的用途是將它們分配給變數:

var foo = function(){ /*...*/ };

foo();

函式作為變數更詳細地介紹了匿名函式的使用

將匿名函式作為引數提供給另一個函式

某些函式可以接受對函式的引用作為引數。這些有時被稱為依賴注入回撥,因為它允許你的呼叫函式回撥你的程式碼,讓你有機會改變被呼叫函式的行為方式。例如,Array 物件的 map 函式允許你遍歷陣列的每個元素,然後通過將變換函式應用於每個元素來構建新陣列。

var nums = [0,1,2];
var doubledNums = nums.map( function(element){ return element * 2; } ); // [0,2,4]

建立一個命名函式將是繁瑣,草率和不必要的,這將使你的範圍變得雜亂,只需要在這一個地方需要的功能,並打破程式碼的自然流程和讀取(同事必須留下此程式碼才能找到你的程式碼)功能,以瞭解正在發生的事情)。

從另一個函式返回匿名函式

有時將函式作為另一個函式的結果返回是有用的。例如:

var hash = getHashFunction( 'sha1' );
var hashValue = hash( 'Secret Value' );

function getHashFunction( algorithm ){

    if ( algorithm === 'sha1' ) return function( value ){ /*...*/ };
    else if ( algorithm === 'md5' ) return function( value ){ /*...*/ };

}

立即呼叫匿名函式

與許多其他語言不同,Javascript 中的作用域是功能級別,而不是塊級別。 (參見函式範圍 )。但是,在某些情況下,有必要建立一個新範圍。例如,在通過 <script> 標記新增程式碼時建立新範圍很常見,而不是允許在全域性範圍內定義變數名(這會冒其他指令碼與變數名衝突的風險)。處理這種情況的常用方法是定義一個新的匿名函式,然後立即呼叫它,安全地將變數隱藏在匿名函式的範圍內,而不會通過洩漏的函式名使第三方訪問你的程式碼。例如:

<!-- My Script -->
<script>
function initialize(){
    // foo is safely hidden within initialize, but...
    var foo = '';
}

// ...my initialize function is now accessible from global scope.
// There's a risk someone could call it again, probably by accident.
initialize();
</script>

<script>
// Using an anonymous function, and then immediately
// invoking it, hides my foo variable and guarantees
// no one else can call it a second time.
(function(){
    var foo = '';
}()) // <--- the parentheses invokes the function immediately
</script>

自引用匿名函式

有時,匿名函式能夠引用自身是有用的。例如,函式可能需要遞迴呼叫自身或向自身新增屬性。但是,如果該函式是匿名的,則這可能非常困難,因為它需要知道已分配函式的變數。這是不太理想的解決方案:

var foo = function(callAgain){
    console.log( 'Whassup?' );
    // Less then ideal... we're dependent on a variable reference...
    if (callAgain === true) foo(false);
};

foo(true);

// Console Output:
// Whassup?
// Whassup?

// Assign bar to the original function, and assign foo to another function.
var bar = foo;
foo = function(){
    console.log('Bad.')
};

bar(true);

// Console Output:
// Whassup?
// Bad.

這裡的意圖是匿名函式以遞迴方式呼叫自身,但是當 foo 的值發生變化時,最終會出現一個可能難以追蹤的錯誤。

相反,我們可以通過給它一個私有名稱給匿名函式一個自己的引用,如下所示:

var foo = function myself(callAgain){
    console.log( 'Whassup?' );
    // Less then ideal... we're dependent on a variable reference...
    if (callAgain === true) myself(false);
};

foo(true);

// Console Output:
// Whassup?
// Whassup?

// Assign bar to the original function, and assign foo to another function.
var bar = foo;
foo = function(){
    console.log('Bad.')
};

bar(true);

// Console Output:
// Whassup?
// Whassup?

請注意,函式名稱的範圍是自身。該名稱尚未洩露到外部範圍:

myself(false); // ReferenceError: myself is not defined

在將遞迴匿名函式作為回撥引數處理時,此技術特別有用:

Version => 五
// Calculate the fibonacci value for each number in an array:
var fib = false,
    result = [1,2,3,4,5,6,7,8].map(
        function fib(n){
            return ( n <= 2 ) ? 1 : fib( n - 1 ) + fib( n - 2 );
        });
// result = [1, 1, 2, 3, 5, 8, 13, 21]
// fib = false (the anonymous function name did not overwrite our fib variable)