最近用setTimeout、setInterval,因爲要傳入的函數要用到this,所以深入瞭解了一番!
setTimeout和setInterval函數的第三個參數本來只是定義語言類型,後來在非IE瀏覽器下支持傳遞參數,並且在不同瀏覽器下支持的不同。
原來的setTimeout函數定義:
var timeoutID = window.setTimeout(func, delay[, lang]);
在Chrome和FF下定義被修改:
var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);
var timeoutID = window.setTimeout(code, delay);
IE:不支持第三個參數。
Chrome:接受的參數=傳遞的參數個數。
FF:接受的參數=傳遞的參數個數+1
具體可參看:https://developer.mozilla.org/zh-CN/docs/DOM/window.setTimeout
建議看了上址,再看本文,效果更好!
程序員是看Code的,貼上一段詳細註釋過的精巧代碼:
(function (w) {
//ie傳入第三個參數
if (! + [1, ]) { //除IE外,!+[1,]都是返回false
(function (overrideFn) {
//overrideFn應改爲wrapCall
w.setTimeout = overrideFn(w.setTimeout);
w.setInterval = overrideFn(w.setInterval);
})(function (originalFn) {//包裝函數,僅供上二行調用,只一個參數一個類setInterval返回函數
originalFn.isPolyfill = true;//fix ie9--
//注意return替換函數,而非調用返回值。返回真正要被替換的setTimeout,setInterval
return function (code, delay) {//這纔是真正的overrideFn
var me = this,//fix: 激活code所在的this作用域
args = Array.prototype.slice.call(arguments, 2);
return originalFn(function () {//這裏才調用原API
if (typeof code == 'string') {
eval(code);
} else {
code.apply(me, args);
}
}, delay);
}
})
}
})(window);
上段代碼修改自:http://mao.li/javascript/javascript-settimeout-params/
很簡練,貓也是自MDN修改而來!我註釋得很詳細,只要理解了匿名函數的調用就通了
現在可以測試一下:
myArray = ["zero", "one", "two"];
myArray.myMethod = function (sProperty) {
alert(arguments.length > 0 ? this[sProperty] : this);
};
setTimeout.call(myArray, myArray.myMethod, 1000);
setTimeout.call(myArray, myArray.myMethod, 1500, 2);
注意二點:還是得用call或apply;傳給setTimeout的回調如果是字符串,則第三參數沒有意義!
上面代碼的另外一點不足之處,就是原setTimeout的“指針”沒有保存到return function (code, delay) {//這纔是真正的overrideFn
這行代碼後的數據中,不過考慮JS也不是原生支持OO,這點缺憾還是可以接受的!
現在,我要重點說說setTimeout的超時調用,特別是在循環中
while (!flag) {
//等待異步完成==>代碼意圖:每30毫秒輪詢異步完成標誌,未完成則等待,讓出執行權響應用戶事件,意圖實現類似sleep效果
setTimeout(null, 30);
}
上面代碼看上去好像沒問題,每30毫秒輪詢異步完成標誌~但是Js是單線程的
所以,這就是段死循環,不停的創建超時計時器,其它代碼沒法變更完成標誌!一二分鐘後就掛了!解決方法,就是回調!
可以用定時器setInterval在回調函數中輪詢異步完成標誌。但最好的辦法還是在異步操作中設置好回調!JS也就這點令人煩,有時大量的回調嵌套三四層,這樣OO代碼實現就有點煩瑣了!
最後點一下,JS引擎單線程,隊列式執行:
setTimeout(fn, 0);//fn不會馬上執行,而是得先前的執行隊列完成才能執行
HTML5中規定:setTimeout最少超時4ms
參考資料:
http://mao.li/javascript/javascript-settimeout-params/
https://developer.mozilla.org/zh-CN/docs/DOM/window.setTimeout