-
方法一
原理:
- 利用
setTimeout
函數的第三個參數,會作為回調函數的第一個參數傳入 - 利用
bind
函數部分執行的特性
代碼 1:
for (var i = 0; i < 10; i++) { setTimeout(i => { console.log(i); }, 1000, i) }
代碼 2:
for (var i = 0; i < 10; i++) { setTimeout(console.log, 1000, i) }
代碼 3:
for (var i = 0; i < 10; i++) { setTimeout(console.log.bind(Object.create(null), i), 1000) }
- 利用
-
方法二
原理:
- 利用
let
變量的特性 — 在每一次for
循環的過程中,let
聲明的變量會在當前的塊級作用域里面(for
循環的 body 體,也即兩個花括號之間的內容區域)創建一個文法環境(Lexical Environment),該環境里面包括了當前for
循環過程中的i
,具體鏈接
代碼 1:
for (let i = 0; i < 10; i++) { setTimeout(() => { console.log(i); }, 1000) }
等價於
for (let i = 0; i < 10; i++) { let _i = i;// const _i = i; setTimeout(() => { console.log(_i); }, 1000) }
- 利用
-
方法三
原理:
- 利用函數自執行的方式,把當前 for 循環過程中的 i 傳遞進去,構建出塊級作用域。IIFE 其實並不屬於閉包的范疇。參考鏈接如下:
- 利用其它方式構建出塊級作用域,如try...catch
代碼 1:
for (var i = 0; i < 10; i++) { (i => { setTimeout(() => { console.log(i); }, 1000) })(i) }
代碼 2:
for (var i = 0; i < 10; i++) { try { throw new Error(i); } catch ({ message: i }) { setTimeout(() => { console.log(i); }, 1000) } }
-
方法四
原理:
- 很多其它的方案只是把
console.log(i)
放到一個函數里面,因為setTimeout
函數的第一個參數只接受函數以及字符串,如果是js
語句的話,js
引擎應該會自動在該語句外面包裹一層函數
代碼 1:
for (var i = 0; i < 10; i++) { setTimeout(console.log(i), 1000) }
代碼 2:
for (var i = 0; i < 10; i++) { setTimeout((() => { console.log(i); })(), 1000) }
代碼 3:
for (var i = 0; i < 10; i++) { setTimeout((i => { console.log(i); })(i), 1000) }
代碼 4:
for (var i = 0; i < 10; i++) { setTimeout((i => { console.log(i); }).call(Object.create(null), i), 1000) }
代碼 5:
for (var i = 0; i < 10; i++) { setTimeout((i => { console.log(i); }).apply(Object.create(null), [i]), 1000) }
代碼 6:
for (var i = 0; i < 10; i++) { setTimeout((i => { console.log(i); }).apply(Object.create(null), { length: 1, '0': i }), 1000) }
- 很多其它的方案只是把
-
方法五
原理:
- 利用 eval 或者 new Function 執行字符串,然后執行過程同方法四
代碼 1:
for (var i = 0; i < 10; i++) { setTimeout(eval('console.log(i)'), 1000) }
代碼 2:
for (var i = 0; i < 10; i++) { setTimeout(new Function('i', 'console.log(i)')(i), 1000) }
代碼 3:
for (var i = 0; i < 10; i++) { setTimeout(new Function('console.log(i)')(), 1000) }