for(var i=1;i<5;i ){setTimeout(function(){console.log(i)},i*1000);}#在這裡for循環是先完成的然後i的值已經變成了5那for迴圈是先執行完的那i*1000為什麼會執行呢
for迴圈執行完時相當於在頁面中寫了4個定時器函數,此時定時器函數還未執行,全域中的i變數值為5;當定時器時間到的時候依序執行定時器函數,依序列印出4個5。
這個例子並不是閉包,閉包需要這樣寫,相當於在頁面中寫了四個立即執行函數,這四個函數接收到的實參依次為1,2,3,4,根據閉包的特性當定時結束時定時器函數可以存取其外層函數所接收到的實參,所以會依序列印出1,2,3,4
for(var i=1;i<5;i++){ (function(i){ setTimeout(function(){console.log(i)},i*1000); })(i) }
在電腦中,任何一個變量,都要在記憶體中開闢一個空間去存儲,然後它們都有一個位址。如果學過c語言或組合語言應該對這個比較清楚。
先說i為什麼每次輸出都是5。因為i的空間(也就是用於儲存i的那段記憶體空間,學名叫「堆疊」)被修改了5次,而那個匿名函數被執行的時候,i的空間中儲存的是5。
再來解釋為什麼第二個參數為什麼每次都不一樣。 i*1000并没有修改i的值,而是会产生一个结果。那么这个结果必然要找地方去存。存储在哪呢?setTimeout每被调用一次,都会开辟一段内存空间,其中一部分空间就用于存储它的两个参数。其中一个参数就是刚才i*1000产生的结果。而setTimeout被调用了5次,于是存储了5个结果!没错,是在5个不同的空间存储了5个结果,而不是像i一樣對同一空間修改了5次!可以想像這種做法是很費內存的。
i*1000
i
setTimeout
這樣解釋能聽懂嗎?
for函數進入主執行緒的時候,每個setTimeout依序進入任務佇列的等待,for執行完後任務佇列中setTimeout進入主執行緒中執行。不加閉包,setTimeout執行的時候i已經是5;加了閉包,setTimeout進入任務佇列的時候i的值會被儲存。 詳見:事件循環
for迴圈執行完時相當於在頁面中寫了4個定時器函數,此時定時器函數還未執行,全域中的i變數值為5;當定時器時間到的時候依序執行定時器函數,依序列印出4個5。
這個例子並不是閉包,閉包需要這樣寫,相當於在頁面中寫了四個立即執行函數,這四個函數接收到的實參依次為1,2,3,4,根據閉包的特性當定時結束時定時器函數可以存取其外層函數所接收到的實參,所以會依序列印出1,2,3,4
在電腦中,任何一個變量,都要在記憶體中開闢一個空間去存儲,然後它們都有一個位址。如果學過c語言或組合語言應該對這個比較清楚。
先說i為什麼每次輸出都是5。因為i的空間(也就是用於儲存i的那段記憶體空間,學名叫「堆疊」)被修改了5次,而那個匿名函數被執行的時候,i的空間中儲存的是5。
再來解釋為什麼第二個參數為什麼每次都不一樣。
i*1000
并没有修改i
的值,而是会产生一个结果。那么这个结果必然要找地方去存。存储在哪呢?setTimeout
每被调用一次,都会开辟一段内存空间,其中一部分空间就用于存储它的两个参数。其中一个参数就是刚才i*1000
产生的结果。而setTimeout
被调用了5次,于是存储了5个结果!没错,是在5个不同的空间存储了5个结果,而不是像i
一樣對同一空間修改了5次!可以想像這種做法是很費內存的。這樣解釋能聽懂嗎?
for函數進入主執行緒的時候,每個setTimeout依序進入任務佇列的等待,for執行完後任務佇列中setTimeout進入主執行緒中執行。不加閉包,setTimeout執行的時候i已經是5;加了閉包,setTimeout進入任務佇列的時候i的值會被儲存。
詳見:事件循環