關于let和var作用域不同導致在異步操作中的不同表現(xiàn)

今天在寫代碼時遇到了個奇怪的問題。

for(var i = 0; i < 10; i++){   
       setTimeout(function() {
           console.log(i)
       }, 1000); 
}

輸出為

10
10
10
10
...

這是個在JavaScript中十分常見的異步問題,出現(xiàn)這種輸出的根本原因在于:

for(var i = 0 ; i<10;i++)

中var i實際上是將i掛載到了全局變量上,當settimeout的回調(diào)函數(shù)執(zhí)行時,i已經(jīng)被for循環(huán)累加到了10,讀取并輸出的自然就是十個10了。
如果想依次輸出0~9該如何呢?在es5之前,有個取巧的方法,就是將i包裹在一個閉包中,將i作為一個函數(shù)的私有變量保存起來,這樣每次settimeout的回調(diào)函數(shù)就可以輸出屬于自己的i了。

但 let 指令可以幫助我們完美的解決這個問題,將上述代碼做一下改造。

for(let i = 0; i < 10; i++){   
       setTimeout(function() {
           console.log(i)
       }, 1000); 
}

可以看出,與最初的代碼唯一的不同,就是將 var i= 0 改為了,let i = 0
測試一下,輸出為

0
1
2
3
..

為什么改了i的聲明方式輸出結(jié)果就會截然不同了呢?
那就要從var與let的不同點說起。
let 與 var 最大的區(qū)別就在于,var 與let 生命的變量的作用域不同。
var 是以函數(shù)作為自己的作用域。
而 let 則是以{ }為作用域。
具體是什么意思呢?就以上邊的代碼為例,for循環(huán)展開后等價于

{
    let i = 0;
    setTimeout(function() {
    console.log(i);
    }, 1000);
}
{
    let i = 1;
    setTimeout(function() {
    console.log(i);
    }, 1000);
}
{
    let i = 2;
    setTimeout(function() {
    console.log(i);
    }, 1000);
}
...

而使用var時則是

var i = 0;
i++;
i++;
i++;
...

{
    setTimeout(function() {
    console.log(i);
    }, 1000);
}
{
    setTimeout(function() {
    console.log(i);
    }, 1000);
}
{
    setTimeout(function() {
    console.log(i);
    }, 1000);
}
...

這么看是不是就直觀了許多?使用let生命的變量,作用域只存在于一個{}之間,所以for循環(huán)一共循環(huán)幾遍,就會有幾個{},每一個{}都會有自己獨有的 i 。
而var則是以函數(shù)為單位,如果沒有外層函數(shù)就會掛載到全局變量上,所有的{}都會共有1個i,自然就會輸出同樣的值了。

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

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容