今天有人在群里问setTimeout第一次参数为字符串的时候为什么会报错,代码如下:
function display(obj) { obj.style.display='none'; window.setTimeout("obj.style.display='inline'", 500); }
报obj is not defined。
经过我自己测试了列子,自己总结出了几个结论,真实性有待考证。下面讲讲我的例子与结论。
首先,setTimeout的第一个参数分为3类,1.字符串代码 2.method 3.function 。
1.字符串代码:
function display(obj) { obj.style.display='none'; window.setTimeout("obj.style.display='inline'", 5000); }
当setTimeout第一个参数为字符串代码时,执行这段代码会报obj未定义,原因是因为setTimeout方法是window的方法,是个全局方法。执行这个方法的代码的作用域环境是window。
obj是当初display方法的参数传进来的,是个局部变量。在window下找不到obj这个变量所以报未定义。
2.method:
在这儿我把method和function区分开了,区别在哪儿呢?代码如下:
function display(obj) { obj.style.display='none'; window.setTimeout("fn(obj)", 5000); } function fn(o){ o.style.display='inline' }
像上面代码一样执行,还是会报obj未定义,原因和上面一样的,这儿调用的fn()是全局方法,它的参数obj在全局变量中找不到。
这个和参数为function的区别在于,method是定义好了方法,当成第一个参数传过setTimeout(),而function是在第一个参数的位置定义function,两者有很大的区别,下面会讲解。
注意,这儿提醒下,我在写代码的时候犯了个错误,代码如下:
function display(obj) { obj.style.diaplay='none'; window.setTimeout(fn(obj),500); } function fn(0){ o.style.display='inline'; }
我把fn(obj)的引号去掉了,这样的写法是错误的,这样写,fn会被立即调用,而不是500毫秒之后。
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是当方法的参数传进来的,所以是能找到的。这样就能正确的执行这段代码。
总结:
要解决这种问题又两个方法,第一:把obj声明成全局变量,setTimeout是可以调用的。全局变量会一直存在,直到页面关闭。
第二种:把setTimeout方法的第一个参数写成function,这样形成一个闭包来访问局部变量。但是闭包会使得它的父函数的变量和方法一直处于内存,直到闭包函数调用结束。
此两种方法各有优缺点,根据自己的需求来取舍。