1. 程式人生 > >閉包問題及解決

閉包問題及解決

閉包的形成

當內部函式被儲存到外部時,會形成閉包;閉包會導致原始作用域鏈不釋放,造成記憶體洩漏(佔用);

例如:

<script type="text/javascript">
	function test(){
		var arr = [];
		for(var i = 0; i < 10; i++){
			arr[i] = function(){
			console.log(i);
			}
		}
		return arr;
	}
	var myArr = test();
	for(var j = 0;j<10;j++){
		myArr[j]();
	}
</script>

最後輸出的結果是10個10;如圖:


我們的目的是輸出0到9,但是結果輸出了10個10,導致這種情況的原因就是閉包;

陣列arr 被儲存到外部,通過for迴圈,相當於將10個函式體儲存到了外部,然後myArr是得到了test()的執行結果,通過函式外的for迴圈順序執行這10個函式體;函式體裡面只有一條語句,就是展示出i的值;

而為什麼打印出來都是10呢?

因為在函式外輸出時,看到的i執行完for迴圈操作後已經變成了10,因為在test()中,我們看到arr[i]被賦值為一個函式,此時這個賦值語句裡面的函式體內容是不執行的,只是讀語句,都宣告和迴圈語句,而賦值語句後面的函式體不執行,只有在呼叫這個函式時,這個函式才執行;

意思就是說,arr[i]這個裡面的i會跟著for迴圈語句一個一個的變,而它後面的函式體裡面的i是不同時隨著一起變的,不知道i為多少,只有當最後函式外面呼叫這個函式體時才會找這個語句裡面i的值(就是最後myArr[j]()呼叫了),而此時i已經變成了10(因為上面for迴圈執行到i = 9時i++,此時i = 10,但是i不滿足判斷條件,賦值語句不執行,但是i已經變成了10);這就是閉包!!!

此時就是10對1;最後執行的函式,索取的i都是同一個i;所以執行了10次,得到十個10;

那怎麼解決這個問題呢?

那麼我們就是要讓上面的函式體,當arr[i]中的i為幾時,相應的函式體裡面的輸出i就為幾,這樣就能解決問題了;

那麼就引入了立即執行函式,只有立即執行函式能解決這個問題,當函數出現的時候就被立即執行,i值的變化直接被變現;程式碼如下:

<script type="text/javascript">
	function test(){
		var arr = [];
		for(var i = 0; i < 10; i++){
			(function(j){
				arr[j] = function(){
					console.log(j);
				}
			}(i));
		}
		return arr;
	}
	var myArr = test();
	for(var j = 0;j<10;j++){
		myArr[j]();
	}
</script>
形參為j,實參為i;for迴圈十次,相當於十個立即執行函式;此時就是有十個函式對應十個引用;
此時,每執行一次i的for迴圈,傳入一個實參,形參j也跟著改變,但此時賦值函式體依舊不執行,當外部執行時,對應的j的for迴圈從0到9剛好對應,此時立即執行函式裡面的j是十個不同的,外部迴圈對應起來找到每個對應的立即執行函式,然後輸出j,此時的結果就是0~9了;


可見,利用立即執行函式解決了問題,得到想要的結果!!!