作用域閉包之 循環(huán)與閉包(1)

今天突然看到群里有童鞋問這樣的一個問題

function fn(){
  var arr=[];
  for(var i=0;i<5;i++){
    arr[i] = function(){
        return i;  
    }
  }
  return arr;
}
var b = fn();
for(var i = 0;i<5;i++){
  console.log(b[i]());
}

第一眼看過去,可能一些接觸js這門語言不太久的童鞋們會認為輸出的結果是0,1,2,3,4
但是執(zhí)行完這段代碼之后卻發(fā)現(xiàn)循環(huán)出來了五次都是5,這是為什么呢?

當然一部分童鞋一眼能看出正確結果,我也相信有的童鞋雖然能知道結果,但是思路并不是特別清晰,今天就來分析下到底為什么會這樣執(zhí)行

這里涉及到了作用域的問題
我們猜想的是每次循環(huán),函數(shù)內部都會捕獲當前i的值

for(var i=0;i<5;i++){
    arr[i] = function(){
        return i;  //0,1,2,3,4
    }
  }

但是根據(jù)作用域的原理,雖然循環(huán)了五次,而且函數(shù)都是在各自的循環(huán)之中定義的,but這里又要說一個但是了,強調下重點它們都被封閉在函數(shù)fn這個函數(shù)作用域之中,因此實際上只有一個i,每次循環(huán)都會給i重新賦值

注意:當fn執(zhí)行的時候循環(huán)執(zhí)行完成,而此時的匿名函數(shù)并沒有執(zhí)行,此刻的i已經在循環(huán)完成之后變成了5,
當執(zhí)行這段代碼的時候

for(var i = 0;i<5;i++){ 
    console.log(b[i]());
}

b[i]會依次調用存儲于arr數(shù)組中的匿名函數(shù),而此刻匿名函數(shù)才開始執(zhí)行,去獲取i的值,因為i都位于fn的函數(shù)作用域下,此刻已經變成了5,所以,自然也就看到了輸出五次5

所以此時的函數(shù)都引用的是同一個i,循環(huán)會誤導你,讓你錯誤的判斷

那么,怎么樣才能避免這種情況,其實改造方法也很簡單,我們利用IIFE,也就是立即執(zhí)行函數(shù),來形成單獨的作用域

function fn(){    
  var arr=[];    
  for(var i=0;i<5;i++){        
    (function(i){            
        arr[i]=function(){                
            return i;            
        }        
    })(i);    
  }    
  return arr;
}
var b = fn();
for(var i = 0;i<5;i++){    
    console.log(b[i]());
}

這樣,在行成獨立的作用域之后,我們就可以拿到當前循環(huán)的i,因為擁有了獨立的作用域,i的值不會再相互影響
當再次調用位于arr數(shù)組中的匿名函數(shù)時,就可以找到儲存于立即執(zhí)行函數(shù)作用域中的i,而此刻的i正式我們希望看到的,會輸出0,1,2,3,4

這是我的一部分理解,如果有理解偏差,歡迎各位童鞋們一起探討

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容