1. 程式人生 > >for迴圈繫結事件時,var和let宣告迴圈變數的區別

for迴圈繫結事件時,var和let宣告迴圈變數的區別

在理解var、let、const三者在宣告變數的區別時,遇到了一道十分有意思的題:

<body>
<ul>
	<li>第一個li</li>
	<li>第二個li</li>
	<li>第三個li</li>
	<li>第四個li</li>
	<li>第五個li</li>
</ul>

<script>

var liList = document.querySelectorAll('li') // 共5個li
for(var i=0; i<liList.length; i++){
  liList[i].onclick = function(){
    console.log(i)
  }
}	
</script>
</body>

以上程式碼中迴圈變數的宣告用var和let會有什麼不同的效果?
結果肯定相信很多人都知道:用var時,都列印5。用let時,列印0、1、2、3、4。


為什麼會這樣,估計很多人就不知道了吧。於是我便講講我的理解:

關鍵點是:1.理解作用域鏈。
  2.var和let的作用域。
  3.變數提升。
詳細講解一下:
鋪墊知識:
1.var宣告變數是函式作用域,而let宣告變數是語句塊作用域;
2.var提升到函式定義頂部,此處是全域性作用域頂部;let提升到語句塊頂部,此處是for迴圈第一行。
3.for( let i = 0; i< 5; i++) 這句話的圓括號之間,有一個隱藏的作用域(用var時沒有)。
  for( let i = 0; i< 5; i++) { 迴圈體 } 在每次執行迴圈體之前,JS 引擎會把 i 在迴圈體的上下文中重新宣告及初始化一次。

正式講解:

1.i的宣告被提升。
2.當執行for迴圈時為i賦值,併為每個li繫結事件(注意:執行for迴圈時只是綁定了事件但是並沒有執行事件)。
3.當觸發事件時(注意:此時for迴圈執行完了),現在需要控制檯列印i的值,於是i便沿著作用域鏈尋找它的值。
4.當用var宣告時,i會在全域性作用域中找到它的值,為5.
5.當用let宣告時,i會在for的第一行找到它的值,每次的值不一樣,分別為0、1、2、3、4.


注:當用let時程式碼可以這樣理解:
var liList = document.querySelectorAll('li') // 共5個li
for( let i=0; i<liList.length; i++){
  let i = 隱藏作用域中的i 
liList[i].onclick = function(){ console.log(i) } }

在不補充點關於變數提升的知識

1.let 的「建立」過程被提升了,但是初始化沒有提升。(此時變數進入暫時死區)
2.var 的「建立」和「初始化」都被提升了。
3.function 的「建立」「初始化」和「賦值」都被提升了。
4.const 和 let 只有一個區別,那就是 const 只有「建立」和「初始化」,沒有「賦值」過程。(也會進入暫時死區)。