在js中,setTimeout()函数是全局变量,无论在哪里它都是全局变量而不是局部变量。所以下面这个例子的结果可能让你大吃一惊:
function A() { this.b = function() { console.log(1) } } var c = new A() setTimeout(c.b, 10)
可能有些人认为上面这个例子输出的结果是1,但是结果是undefined。这是因为setTImeout()函数是全局变量,它把里面的c.b发到全局变量中,而全局变量中没有b这个属性,所以返回的undefined。
在js中,setTimeout()函数的运行机制是这样的,setInterval()函数也一样。将指定的代码移出本次执行,等到下一轮Event Loop时,再检查是否到了指定时间。如果到了,就执行对应的代码;如果不到,就等到再下一轮Event Loop时重新判断。这意味着,setTimeout指定的代码,必须等到本次执行的所有代码都执行完,才会执行。·
每一轮Event Loop时,都会将“任务队列”中需要执行的任务,一次执行完。setTimeout和setInterval都是把任务添加到“任务队列”的尾部。因此,它们实际上要等到当前脚本的所有同步任务执行完,然后再等到本次Event Loop的“任务队列”的所有任务执行完,才会开始执行。由于前面的任务到底需要多少时间执行完,是不确定的,所以没有办法保证,setTimeout和setInterval指定的任务,一定会按照预定时间执行。
所以如果前面有一个函数被阻塞了,则一直等待该函数执行完才能运行。因为js是单线程的,所以比较容易会发生阻塞的。
在setTimeout()函数中,最快的运行时间是4毫秒,即使将延迟参数写为0或者负数,它都不会立马的运行。在延迟参数为0或负数时,需要等待当前脚步的同步任务和event loop(即任务队列)执行完毕才开始执行,由于参数为0或者负数,只是比其他setTimeout()函数尽可能早的运行函数,而参数为0或者负数本身优先级相同。如:
setTimeout('console.log(1)',0) console.log(2)
返回的结果是2 1
setTimeout('console.log(1)',0) setTimeout('console.log(2)',-1) setTimeout('console.log(3)',-1) setTimeout('console.log(4)',0)
返回的结果是1 2 3 4
在setTimeout()函数中,还有一点是要值得注意的。那就是它的第一个参数必须是需要编译的代码或者是一个函数方法。所以像上面的例子中,console.log()被单引号括起来变成一个字符串,在setTimeout中有一个eval()函数可以将字符串进行编译。如果我们将console.log()方法没有用单引号括起来,那么整个setTimeout()函数就会立即执行,而不会考虑有没有延迟参数。如我在美的的美云智数面试遇见过的这一道题一样:
console.log(1) setTimeout(console.log(2),0) console.log(3) setTimeout(console.log(4),-1)
返回的结果是1 2 3 4,如果将单引号括起来,返回的结果是1 3 2 4
在js中想要清除setTimeout定时器,需要clearTimeout()这个函数。具体用法如下所示:
var a = setTimeout('console.log(1)', 1) clearTimeout(a)
最后贴出一道题看看毕业了没有,对比下面三段代码,看分别输出上面:
for (var i = 0; i < 3; i++) { setTimeout(function() { console.log(i); }, 0); console.log(i); }
for (var i = 0; i < 3; i++) { setTimeout((function() { console.log(i); })(i), 0); console.log(i); }
for (var i = 0; i < 3; i++) { setTimeout((function(i) { return function() { console.log(i); }; })(i), 0); console.log(i); }
这道题设计了一些js的作用域的问题,我会专门写一篇文章介绍es5中作用域和es6中的作用域发生了哪些变化。
以上是js中的setTimeout()函数的详细内容。更多信息请关注PHP中文网其他相关文章!