簡體   English   中英

如何解釋結果(了解js中的let和var)

[英]how to interpret the result ( understand let and var in js)

考慮以下代碼

 var fs = []; for(var i=0;i<10;i++){ fs.push(i => console.log(i)); } fs.forEach( f => f()); 

如果功能更改為:

for(let i=0;i<10;i++){
    fs.push(function(){
        console.log(i)
    });
}

它將打印1,2,3,4,5,6,7,8,9預期輸出。

我不明白為什么。 有人可以幫忙嗎?

let和var 對於為什么 undefined 10倍的代碼 undefined

確實有所不同的是,您的箭頭函數是使用參數i定義的(覆蓋外部索引i ),而在第二個示例中則不是。

 const fs = []; for (var i = 0; i < 10; i++) { fs.push(() => console.log(i)); } fs.forEach(f => f()); 

如果將該參數添加到第二個示例中,則還會得到10x undefined

 const fs = []; for (let i = 0; i < 10; i++) { fs.push(function(i) { console.log(i) }); } fs.forEach(f => f()); 

varlet在代碼中的區別更加細微:

 const fs = []; for (var i = 0; i < 10; i++) { fs.push(() => console.log(i)); } fs.forEach(f => f()); 

 const fs = []; for (let i = 0; i < 10; i++) { fs.push(() => console.log(i)); } fs.forEach(f => f()); 

使用let時,數組中的每個函數都有一個局部范圍內的閉包i ,而使用var在執行時, i10 (因為每個函數中只有一個變量i被閉包)。

有2個不同的問題需要詳細介紹。 讓我們集中討論第一種情況,主要問題是定義ES6箭頭函數,然后在不使用參數的情況下調用它:

當轉換為ES5匿名函數表示法時, i => console.log(i)為:

function(i){ console.log(i) }

因此,在i => console.log(i) ,您可以看到一個接受參數i的匿名函數的簡寫ES6定義(也稱為ES6箭頭函數符號 )。

最終結果是console.log(i)嘗試打印undefinedi ,因為在執行時未將其傳遞給該arrow函數

您重新推送了一個函數定義,稍后您將在 向其傳遞參數的情況下執行該定義,該參數實際上需要在控制台中將其輸出。

 var fs = []; for(var i=0; i<10; i++){ // You are pushing to the array the below anonymous function definition fs.push( // You are creating an anonymous function which accepts i and console.logs it i => console.log(i) ); } fs.forEach( // You are calling the "pushed" above function definition with NO parameter i f => f() ); 

現在讓我們探討第二個代碼示例的原因和方式,以及var/let如何在控制台輸出中發揮重要作用:

 let fs = [] // You define i in the for-loop block score for(var i=0; i<10; i++){ fs.push( // You push an annonymous function definition wich has a reference of i in the same block scope // However i is already here 10 since the loop is already done and it takes the last value of i function(){ console.log(i) } ); } fs.forEach( // You call f which has a reference inside to the i from the for loop f => f() ); 

因此,在這種情況下, i當你使用var ii ,因為它不保留其詞法塊范圍最終被更新為10的的console.log被調用之前。

現在letlet嘗試let

 let fs = [] // You define i via LET in the for-loop block score for(let i=0; i<10; i++){ fs.push( // You push an annonymous function definition wich has a reference of i in the same block scope // i retains its lexical scope in for loops function(){ console.log(i) } ); } fs.forEach( // You call f which has a reference inside to the i from the for loop f => f() ); 

讓讓更多:

let允許您聲明范圍限於使用 語句表達式的變量。 var關鍵字 不同 ,var關鍵字 在全局范圍內或整個函數本地定義變量,而不管塊范圍如何。

在第一示例中, ifs.push(i => console.log(i)); 是箭頭功能的參數。 這實際上等效於fs.push(function(i){ return console.log(i); });

此參數與循環的迭代器具有相同的名稱。 在要推送的功能范圍內,參數i優先於外部變量。 如果要捕獲迭代器,則不應將其命名為與參數相同的名稱,如下所示:

fs.push(() => console.log(i));

現在您將看到在這種情況下varlet之間存在區別。 您的輸出將是10,10,10,10,10,10,10,10,10,10,10。 這是因為varlet的作用域不同。 當使用var聲明時,循環迭代器在整個循環過程中將是同一對象。 所有功能都捕獲相同的對象。 循環結束后( i++發生,然后進行條件檢查)的最終值為10,因此它們全部顯示為10。使用let ,迭代器在循環的每次迭代中都是一個新對象,因此每個函數都捕獲一個新對象,該對象持有當前循環數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM