關於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的一些黑魔法,以防到時候懵逼。

相關文章
相關標籤/搜索