閉包與作用域再次深究
阿新 • • 發佈:2019-09-24
最近看到一個有意思的函式
function test (arr) { var temp = [] for (var i =0; i<arr.length; i++) { (function() { var j = i; temp[i] = function () { return j } })() } return temp }
那麼以下的結果會打印出什麼呢?
var arr = [1,2,3,4,5] var arrFn = test(arr) console.log(arrFn[0])
結果是:0;
那麼繼續test函式換成以下兩種又會是什麼結果呢?
function test2 (arr) { var temp = [] for (var i =0; i<arr.length; i++) { temp[i] = function () { return i } } return temp }
function test3 (arr) { var temp = [] for (var i =0; i<arr.length; i++) { (function() { temp[i] = function () { return i } })() } return temp }
test2是網上比較常見的,結果是我們在讀取i的時候,i已經全部變為5;test3和test只有兩行程式碼不同,但是結果卻完全不一樣。
之前曾經理解是因為我們呼叫的時候for迴圈已經執行完,所以會拿到i為5。但是其實這只是表象,最核心的其實只有一句話:
閉包通過引用而不是值(非引用)來獲取他們外部的變數
因為是引用型別,所以在for執行完之後,i變為了5,引用型別也就繼而變為5.
在test中添加了一行可以驗證的程式碼就是:
var j = i;
通過在區域性作用域宣告非引用型別,將單次迴圈是的引用型別儲存下來,那麼就能獲取我們想要的結果了。
還有其他方法,通過自執行函式傳遞引數,將引用型別變為非引用型別都是一個原理:
function test4 (arr) { var temp = [] for (var i =0; i<arr.length; i++) { (function(j) { temp[i] = function () { return j; } })(i) } return temp }
其次就是在IIFE來建立區域性作用域的時候,需要注意不能再作用域外部使用break與continue,這樣的寫法是不合法的。
&n