题目为何叫setTimeout的第一个参数而不是回调函数?若是你心中有稍有疑惑,或许应该看看下面的文章javascript
咱们平常使用setTimeout(),通常是将函数做为第一个参数,可是也有例外状况,先看如下代码:java
function test() { var cl = function() { console.log(666) } setTimeout('cl()', 1500) } test()
将以上代码CV到chrome中的console,运行发现:chrome
Uncaught ReferenceError: cl is not defined闭包
没有定义cl函数,奇怪是并无报Uncaught SyntaxError: Unexpected identifier
这样的语法错误,查javascript MDN咱们就会发现:xss
setTimeout容许讲一个字符串做为第一个参数,并且js内部将会调用eval()函数用来动态执行一段字符串脚本,至于为何找不到cl函数,咱们猜测是做用域问题,既然是eval动态执行,咱们在字符串参数中输出当前this绑定的对象:ide
function test() { var cl = function() { console.log(666) } setTimeout('console.log(this);cl()', 1500) } test()
执行后发现:函数
原来this绑定window全局对象,这下明白了,eval()执行动态脚本的时候,在全局做用域并无找到咱们定义在函数test内部的cl,因此会报错。this
咱们将cl定义移到外部:code
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的一些黑魔法,以防到时候懵逼。