JavaScript之閉包與當即執行函數

閉包與當即執行函數


前言:最近在細讀Javascript高級程序設計,對於我而言,中文版,書中不少地方翻譯的差強人意,因此用本身所理解的,嘗試解讀下。若有紕漏或錯誤,會很是感謝您的指出。文中絕大部份內容引用自《JavaScript高級程序設計第三版》。數組


做用域鏈的這種配置機制引出了一個值得注意的反作用,即閉包只能取得包含任何變量的最後一個值。閉包

function createArray(){

    var result = new Array();

    for(var i = 0; i < 10; i++) {
        result[i] = function() {
            return i;
        }
    }

    return result;
}

這個函數會返回一個函數數組。表面上看,彷佛每一個函數都應該返回本身的索引值,即位置0的函數返回0,位置1的函數返回1, 以此類推。函數

但實際上,每一個函數都返回10,由於每一個函數的做用域中都保存着createArray的活動對象,因此他們引用的都是同一個變量i。翻譯

當createArray()函數返回後,變量i的值是10,此時每一個函數都引用着同一個變量i,因此i的值是10。設計

// 代碼執行過程

createArray();

/*
createArray() {
    var result = new Array();

    var i; // 0,1,2,3,4,5,6,7,8,9,10

    for ( i = 0; i < 10 ; i ++) {
        result[i] = function() {
            return i; 
            // 注意 函數的執行時機,你只有調用函數的時候,纔會產生執行環境,沿着做用域鏈,找到活動對象
            // 這裏有個閉包,還記得閉包的概念嗎? 有權訪問到另一個函數做用域的變量的函數
        }
    }
    
    /*
    result[0] = function(){
        return i
    }
    result[1] = function(){
        return i
    }
    result[2] = function(){
        return i
    }
    ....
    */
    return result;
}

result = [function(){return i}, function(){return i}....];

*/

createArray()[1](); // 10

那麼如何讓這個函數的行爲符合咱們的預期呢?code

能夠經過建立另外一個匿名函數強制讓閉包的行爲符合預期,這裏也應用了當即執行函數。對象

//當即執行函數
//咱們平時寫函數而後調用是這麼寫的。
//聲明函數,調用執行。

function foo(){
    console.log("hi");
}

foo(); // "hi"

//那麼,咱們可不能夠聲明調用寫一塊呢? 這就是申明函數馬上執行。
//好像不能夠,控制檯報錯

function foo(){
    console.log("hi");
}(); //Uncaught SyntaxError: Unexpected token )


//那麼若是用括號包裹呢?

(function foo(){
    console.log("hi");
}()); // "hi", 能夠了。 這就是當即執行函數!

有了當即執行函數,就能夠強制讓閉包的行爲符合咱們的預期了。索引

//改寫代碼

function createArray() {

    var result = new Array();

    for( var i = 0; i < 10; i ++ ) {
        result[i] = (function(i) { 
            return function(){
                return i;
            }
        }(i));
    }

    return result;

}

createArray()[0](); // 0
createArray()[1](); // 1
createArray()[2](); // 2 

// 這裏不僅有一種方法,其餘方法在此不表。
相關文章
相關標籤/搜索