题目如下, fn1() 和 fn2() 结果?
function fn1() {
for (var i = 0; i < 4; i++) {
var tc = setTimeout(function (i) {
console.log(i);
clearTimeout(tc);
},10, i)
}
}
function fn2() {
for (var i = 0; i < 4; i++) {
var tc = setInterval(function (i, tc) {
console.log(i);
clearInterval(tc);
}, 10, i, tc)
}
}
fn1();
fn2();
答案:
fn1(); // 0,1,2
fn2(); // 0,1,2,3,3,3,3,3.....
解析:
function fn1() {
for (var i = 0; i < 4; i++) {
var tc = setTimeout(function (i) { // var 变量回被提升,变量值会被后面覆盖
console.log(i); // 打印定时器被传进来的参数i
clearTimeout(tc); // tc变量最后的值是最后一个定时器的ID: 4
},10, i) // i 的传参会一直被保留,知道定时器启动时被调用
}
}
function fn2() {
for (var i = 0; i < 4; i++) {
var tc = setInterval(function (i, tc) {
console.log(i); // 打印定时器被传进来的参数i
clearInterval(tc); // 这里的 tc 是每次被传进来的定时器的ID
}, 10, i, tc) // 传参的 i, 和定时器ID值 tc 会被保留
}
}
这道题涉及定时器的传参和返回值,以及JS执行顺序异步问题。
定时器语法:
var intervalID = scope.setInterval(func, delay, [arg1, arg2, ...])
var timeoutID = scope.setTimeout(function[, delay, arg1, arg2, ...])
第一个参数func是执行函数,第二个参数 dalay 是延迟时间, 后面的参数都是传给执行函数的参数。
定时器的返回值是定时器的计数器,从1开始计数,表示定时器的ID, 这个ID 传递给 clearInterval() 和 clearTimeout() 来清除定时器。注意,intervalID 和 timeoutID 会公用一个编号池。
异步任务:
定时器在JS中被作为异步任务,放到任务队列中,当主线程任务执行完之后,会来执行异步任务。