
图1:setTimeOut语法【1】
setTimeout的第一个参数分为3类,1.字符串代码 2.method 3.function【2】 。
1.字符串
function display(obj)
{
obj.style.display='none';
window.setTimeout("obj.style.display='inline'", 500);
}
上面的这个代码会报错,obj is not defined。
因为setTimeout方法是window的方法,是个全局方法。执行这个方法的代码的作用域环境是window。
obj是当初display方法的参数传进来的,是个局部变量。在window下找不到obj这个变量所以报未定义。
2.封装后的方法传入 - method
function display(obj)
{
obj.style.display='none';
window.setTimeout("fn(obj)", 5000);
}
function fn(o){
o.style.display='inline'
}
这样写 obj is not defined
原因和上面一样的,这儿调用的fn()是全局方法,它的参数obj在全局变量中找不到。
这里有一个注意点就是 window.setTimeout("fn(obj)", 5000); 这一句内的 fn(obj) 双引号双引号去掉以后会立即执行,当然,这个是错误的,举个例子
同时,抛出一个问题【3】

结果是立即输出0,1,2,3,4
【4】(下面是相应问题的回答,我做了部分修改和添加还有验证)网上关于JS预解释的文章也不少,在进入执行上下文阶段的时候函数并不会执行,简单来说就是当你声明这个函数的时候,只要不调用就不会执行,上下文里面只会保存着这个函数的引用,可以看做这个函数保存在内存中,只有到调用的时候函数才会执行。
你在for循环里面实际上相当于定义了5个定时器,但是js是单线程,这五个函数会被放到队列里面等待执行,你的函数内有立即执行函数,像你在for循环里面实际上相当于定义了5个定时器,但是js是单线程,这五个函数会被放到队列里面等待执行。
(function(i) {
return function() { console.log(i); }})(i)
但是由于里面是立即执行函数,相当于执行上面一段,所以会立即就执行了,并且把i传了进去,等到这五个函数执行的时候,向上查找i,正好在这个立即调用函数的作用域里面查找到了i,所以会打印出0、1、2、3、4.
建议这样写(这是答主的提议)

但我个人建议这样写

每次将i作为参数传到setTimeout函数内(把(i)放在第一个函数后面也是这个原理,但不太严谨)
3.将function直接写在第一个参数处
function display(obj)
{
obj.style.diaplay='none';
window.setTimeout(function(){ obj.style.display='inline';},500);
}
这种写法是把function直接写在了setTimeout的第一个参数位置,这样写就和display()形成了一个闭包。所以setTimeout执行function的时候display的作用域是存在的。
这样就会先去display()的作用域找obj这个变量,obj是当方法的参数传进来的,所以是能找到的。这样就能正确的执行这段代码。
PS1:第一个参数如果要用函数,一般要处理为setTimeOut(“function name()” ,time) (这时理解为匿名函数,也可以在里面直接执行一句话),或者setTimeOut(function name ,time) 或者setTimeOut(function name(){} ,time) ,setTimeOut(function name() ,time) 意味着执行返回值而不是函数,这时会立即执行函数,之后将返回值传入setTimeout方法
PS2: 有关timer=0
事实上,上面的代码并不是立即执行的,这是因为setTimeout有一个最小执行时间,当指定的时间小于该时间时,浏览器会用最小允许的时间作为setTimeout的时间间隔,也就是说即使我们把setTimeout的延迟时间设置为0,被调用的程序也没有马上启动。
不同的浏览器实际情况不同,IE8和更早的IE的时间精确度是15.6ms。不过,随着HTML5的出现,在高级版本的浏览器(Chrome、ie9+等),定义的最小时间间隔是不得低于4毫秒,如果低于这个值,就会自动增加,并且在2010年及之后发布的浏览器中采取一致。
所以说,当我们写为 setTimeout(fn,0) 的时候,实际是实现插队操作,要求浏览器“尽可能快”的进行回调,但是实际能多快就完全取决于浏览器了。
那setTimeout(fn, 0)有什么用处呢?其实用处就在于我们可以改变任务的执行顺序!因为浏览器会在执行完当前任务队列中的任务,再执行setTimeout队列中积累的的任务。
通过设置任务在延迟到0s后执行,就能改变任务执行的先后顺序,延迟该任务发生,使之异步执行【5】。
参考文献
【1】菜鸟联盟 , Window setTimeout() 方法 ,https://www.runoob.com/jsref/met-win-settimeout.html 2013
【2】 过眼云烟之活在当下, setTimeout 第一个参数,https://www.cnblogs.com/webhelper/p/3711888.html, 2014.5.6
【3】鱼娟娟, setTimeout第一个参数是立即执行函数,看不懂了, https://segmentfault.com/q/1010000009490850/a-1020000009490859 2017.5.20
【4】尹光耀 setTimeout第一个参数是立即执行函数,看不懂了, https://segmentfault.com/q/1010000009490850/a-1020000009490859 2018.5.20
【5】技术空间 . setTimeout 使用方法详解 . https://blog.youkuaiyun.com/m0_37290635/article/details/56685944 . 2017.2.23
本文详细探讨了setTimeout的第一个参数的三种类型:字符串代码、方法和直接传入的函数。通过实例解析了为何字符串代码和方法可能导致`obj is not defined`的错误,强调了在使用方法时应注意的作用域问题。此外,还讨论了将function直接作为参数时形成的闭包以及如何正确处理函数参数以确保代码按预期执行。最后,提到了浏览器对最小执行时间的限制以及利用setTimeout实现任务异步执行的策略。
919






