從實現倒計時談閉包

面試中在談論閉包的時候有讓實現一個倒計時功能,當時滿腦子都是那個setTimeout壓入棧不斷輸出循環尾數的例子,最後也是沒有用閉包實現倒計時

首先來看看那個在循環中不斷重複輸出的setTimeout代碼片:

var countDown = function(){
  		for(var i=10;i>0;i--)
  		{
  			setTimeout(function(){console.log(i);},1000);
  		}
  }



輸出效果:


當然這個是沒有實現倒計時功能的,原因呢:

首先,和setTimeout設置的時間是沒有關係的,很多人懷疑是時間設置的問題,不信可以將時間設置爲0,結果是一樣的,這裏就不演示了

當然,得分析分析setTimeout的循環機制:setTimeout是從隊列結束的時候開始計時的,如果前面有進程沒有結束,那麼它就等到它結束再開始計時,在這裏呢,任務隊列就是它自己所在的循環。循環結束setTimeout纔開始計時,所以無論如何,setTimeout裏面的i都是最後一次循環的

解決方法呢如下:

 var countDown = function(){
  		for(var i=10;i>0;i--)
  		{
  			var a =function(v){
  				return function(){
  					console.log(v);
  				}
  			}
  			setTimeout(a(i),1000);
  		}
  }



因爲setTimeout的第一個參數需要一個函數,所以返回一個函數給他,返回的同時把i作爲參數傳進去,通過形參v緩存了i,並帶進返回的函數裏面


當然了,這樣寫也是可以的:

var countDown = function(){
  		for(var i=10;i>0;i--)
  		{
  			var a =function(v){
  				
  					console.log(v);
  			
  			}
  			setTimeout(a(i),1000);
  		}
  }


總之呢:例子中遇到setTimeout的問題,原因就是回調等待循環隊列結束造成的,解決的辦法就是給回調函數傳一個實參緩存循環的數據



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章