前言:最近在細讀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 // 這裏不僅有一種方法,其餘方法在此不表。