关于setTimeout 第一个参数的问题解析

题目为何叫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的一些黑魔法,以防到时候懵逼。

相关文章
相关标签/搜索