js面試題:let和var配合定時器中使用

一、let和var的區別

//let和var的區別相信列位已經耳熟能詳了,在這裏不做過多陳述,在第二段將用到的會提及一下

二、在定時器中的表現

  • var
	  for (var i = 0; i < 5; i++) {
            setTimeout(function () {
                console.log("定時器" + i);
            })
        }

		//5 * 定時器5

  • let
	for (let i = 0; i < 5; i++) {
            setTimeout(function () {
                console.log("定時器" + i);
            })
        }
         //定時器0
		 //定時器1
		 //定時器2
		 //定時器3
		 //定時器4

三、解析

(1)產生這種的原因有三個

  • let聲明帶來的塊級作用域
  • for循環機制(重點)
  • var的變量提升

(2) var命令做了什麼

  • var首先帶來了變量提升,將i提升到全局變量,所以var命令實際上只執行了一次
    //在es6之前,js只有全局和局部作用域概念,局部作用也可以理解成函數作用域,所以此時在for循環用var聲明的變量是全局變量
  • 其次定時器是宏任務隊列,for循環在這裏相當於在Event Queue添加了五個事件
  • 最後主線程任務執行結束後開始調用Event Queue中的事件,因爲var帶來的變量提升,此時全局只能有一個變量i,而i在for循環迭代到5,所以此時5個setTimeout事件中的i都指向了5

(3)let命令做了什麼

  • let命令不存在變量提升,所以在每次for循環執行中let都會執行一次
  • let塊級作用域鎖區,所以當前的作用域內也只有一個i
  • 所以每個setTimeout中的i值都指向了不同的值

(4)for命令做了什麼

  • for 循環機制決定了它每次循環都是不同的塊級作用域(這裏與let聲明塊級作用域吻合)
  • 根據阮一峯的<<ES6入門>>:JavaScript 引擎內部會記住上一輪循環的值,初始化本輪的變量i時,就在上一輪循環的基礎上進行計算。(實現了i初始化)

四、總結

簡單點說,實現輸出0 1 2 3 4的需求的原理就是利用了js中for循環機制和let的無變量提升和塊級作用域

實際上 用 let 也能實現 var 同樣的需求(代碼如下)

		let i = 0;
        for (; i < 5; i++) {
            setTimeout(function () {
                console.log("定時器" + i);
            })
        }
		//5 * 定時器5
		//這裏能實現的原因就是手動實現了一個變量提升
		//此時在setTimeout事件中都是對i的引用而不是賦予一個新值
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章