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)的情況下,很有用途。