setInterval()和setTimeout()的兩種使用方式及作用域

setInterval()是以指定的時間爲週期調用函數的方法。

setTimeout()是延時指定的時間來執行某個函數的方法。

兩個函數雖然作用不同,但傳參方式和作用域是相同的,下面來具體分析一下。

以setInterval()爲例:

第一個參數是用來傳遞要調用的方法,可以傳遞一個代碼串,如下:

1 <script>
2     function fn(value){
3         alert("value=" + value);
4     }
5     setTimeout("fn(1)", 1000);
6 </script>

但是當在一個閉包裏調用的時候,就會出現問題,如:

 1 <script>
 2     function outerFn(){
 3         var value = 1;
 4         function fn(){
 5             alert("value=" + value);
 6             value += 1;
 7         }
 8         setInterval("fn()", 3000);
 9     }
10     outerFn();
11 </script>

會出現錯誤:Uncaught ReferenceError: fn is not defined

原因是fn()是以字符串的方式傳遞的,它的作用域是全局作用域,全局作用域是無法訪問到fn()的。

解決的辦法是fn以函數引用的方式傳遞,也就是setInterval()的第二種傳參方式。

 1 <script>
 2     function outerFn(){
 3         var value = 1;
 4         function fn(){
 5             alert("value=" + value);
 6             value += 1;
 7         }
 8         setInterval(fn, 3000);
 9     }
10     outerFn();
11 </script>

但是這樣又帶來問題,如果想給fn傳參數怎麼辦?可以像如下這樣去寫嗎?

 1 <script>
 2     function outerFn(){
 3         var value = 1;
 4         function fn(n){
 5             alert("value=" + n);
 6         }
 7         setTimeout(fn(5), 1000);
 8     }
 9     outerFn();
10 </script>

答案是不可以的,函數只寫函數名,是函數引用;後面加括號是函數執行。

1 setTimeout(fn, 1000); //fn的引用
2 setTimeout(fn(5), 1000);  //fn直接執行

所以第7行,沒有按照預期延遲1000毫秒執行fn(5),而是立刻就執行了。這要注意和上面第一種方式——傳遞代碼字符串的不同。

如果確實有從外部傳參的需要,該怎麼辦呢?

1 <script>
2     function outerFn(value){
3         function fn(){
4             alert("value=" + value);
5         }
6         setTimeout(fn, 1000);
7     }
8     outerFn(5);
9 </script>

如上,是利用了閉包的原理,fn作爲內部函數,是可以訪問包含它的outerFn的作用域中的變量的,因此我們想給fn傳參,只要給outerFn傳參就可以了。這在傳遞的參數複雜(比如是一個複雜的json)的情況下,很有用途。

發佈了31 篇原創文章 · 獲贊 3 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章