题目为何叫setTimeout的第一个参数而不是回调函数?假如你心中有稍有迷惑,也许应当看看下面的文章
我们一样平常运用setTimeout(),平常是将函数作为第一个参数,然则也有例外情况,先看以下代码:
function test() {
var cl = function() {
console.log(666)
}
setTimeout('cl()', 1500)
}
test()
将以上代码CV到chrome中的console,运转发明:
Uncaught ReferenceError: cl is not defined
没有定义cl函数,新鲜是并没有报Uncaught SyntaxError: Unexpected identifier
如许的语法错误,查javascript MDN我们就会发明:
setTimeout许可讲一个字符串作为第一个参数,而且js内部将会挪用eval()函数用来动态实行一段字符串剧本,至于为何找不到cl函数,我们猜测是作用域题目,既然是eval动态实行,我们在字符串参数中输出当前this绑定的对象:
function test() {
var cl = function() {
console.log(666)
}
setTimeout('console.log(this);cl()', 1500)
}
test()
实行后发明:
本来this绑定window全局对象,这下邃晓了,eval()实行动态剧本的时刻,在全局作用域并没有找到我们定义在函数test内部的cl,所以会报错。
我们将cl定义移到外部:
ok了
————分割线————
var cl = function() {console.log(666)}
setTimeout(cl(), 1500)
常常看到有新人在社区上问这段代码为何没有耽误实行,只需注重这边的cl()是一个函数实行而不是函数定义,假如想耽误实行,我们须要通报一个函数地点,比方:
var cl = function() {console.log(666)}
setTimeout(cl, 1500)
或许直接return一个函数:
var cl = function() {
return function() {
console.log(666)
}
}
setTimeout(cl(), 1500)
又或许参数处直接定义:
setTimeout(function() {console.log(666)}, 1500)
归根结柢照样搞清援用函数地点和实行函数的区分
————分割线————
以上划定规矩也一样适用于字符串参数,只是字符串参数中要加上()保证eval的时刻实行,不要到时刻只是eval了一个地点 =。=,比方如许:
var cl = function() {
console.log(666)
}
function test() {
setTimeout('cl', 1500)
}
test()
实行一下,啥屁也没看到 = 。=
总之,在setTimeout的时刻只管不要用字符串的参数,由于eval()具有很多不可预感的危险性,比方说能够有不测的运转效果,能够隐式建立全局变量,闭包作用域剖析过量斲丧,xss,运转慢啊巴拉巴拉之类的。然则我们也须要了解下js的一些黑魔法,以防到时刻懵逼。