成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

談?wù)?setTimeout 這道經(jīng)典題目

Sleepy / 2286人閱讀

摘要:談?wù)勛约簩ο旅孢@道題目的理解問題這段代碼的輸出是三次,與預(yù)想的,,的輸出不符。此外,還可以使用下面這種方式這里可以使用閉包的知識進行解釋有關(guān)閉包的內(nèi)容可以參見文末的參考鏈接,也可以用作用域輔助理解。

談?wù)勛约簩ο旅孢@道題目的理解

問題
for (var i = 1; i <= 3; i++) { 
    setTimeout( function timer() {
        console.log(i);
    }, i * 1000 );
}

這段代碼的輸出是三次 4,與預(yù)想的 1,2,3 的輸出不符。以下解釋這一輸出的原因。

分析

我們可以將 setTimeout 的第一個參數(shù) timer() 多帶帶寫出來,變成如下代碼:

for (var i = 1; i <= 3; i++) { 
    function timer() {
        console.log(i);
    }
    setTimeout( timer, i * 1000 );
}

然后我們將循環(huán)展開,三次執(zhí)行過程的變化如下:

// 第一步: i = 1;
setTimeout( timer, 1 * 1000 );

// 第二步:i = 2;
setTimeout( timer, 2 * 1000 );

// 第三步 i = 3;
setTimeout( timer, 3 * 1000 );

注意,在循環(huán)過程中,timer() 函數(shù)并未變化,也沒有執(zhí)行( 計時器還未開始 )。

由于 JavaScript 中使用 var i = xxx 聲明的變量是函數(shù)級別( 而非塊級 )的作用域,因而在 for 循環(huán)條件中聲明的 i 在 for 循環(huán)塊之外的最后一個函數(shù)體內(nèi)仍是可以訪問的,循環(huán)可以展開為:

var i = 4;
function timer() {
    console.log(i);
}
setTimeout( timer, 1 * 1000 );
setTimeout( timer, 2 * 1000 );
setTimeout( timer, 3 * 1000 );

因而當(dāng)計時器開始的 1s, 2s, 3s 后,timer 會分別執(zhí)行,此時會輸出三次 4。

解決方法

若要其每隔 1s 分別輸出 1, 2, 3,可以將 var i = 1 修改為 let i = 1,即:

for (let i = 1; i <= 3; i++) { 
    function timer() {
        console.log(i);
    }
    setTimeout( timer, i * 1000 );
}

注意,由于 let 屬于 ES6 的語法,請注意測試使用的瀏覽器。

此時,由于 let i = xxx 為塊級別作用域,因而這一情況下的循環(huán)展開結(jié)果為:

{
    let i = 1;
    setTimeout( timer, 1 * 1000 );
}
{
    let i = 2;
    setTimeout( timer, 2 * 1000 );
}
{
    let i = 3;
    setTimeout( timer, 3 * 1000 );
}

注意:這里的 {} 僅用來強調(diào)塊級別作用域。

此時便可以得到我們想要的輸出結(jié)果了。

此外,還可以使用下面這種方式:

for (var i = 1; i <= 3; i++) { 
    (function(count){
        setTimeout( function timer() {
            console.log(count);
        }, count * 1000 );
    })(i)
}

這里可以使用閉包的知識進行解釋( 有關(guān)閉包的內(nèi)容可以參見文末的參考鏈接 ),也可以用作用域輔助理解。

由于 var i = xxx 是函數(shù)級別作用域,這里通過一個立即函數(shù)將變量 i 傳入其中,使其包含在這一函數(shù)的作用域中。而在每次循環(huán)中,此立即函數(shù)都會將傳入的 i 值保存下來,因而其循環(huán)展開結(jié)果為:

(function(){
    var count = 1;
    setTimeout( function timer() {
        console.log(count);
    }, count * 1000 );
})()
(function(){
    var count = 2;
    setTimeout( function timer() {
        console.log(count);
    }, count * 1000 );
})()
(function(){
    var count = 3;
    setTimeout( function timer() {
        console.log(count);
    }, count * 1000 );
})()

自然也會得到我們想要的輸出結(jié)果。

擴展 - 塊級作用域和函數(shù)級作用域

可以用以下代碼進行解釋:

{
    let i = 2;
    // 輸出 2
    console.log(i);
}
// 報錯:Uncaught ReferenceError: i is not defined
console.log(i);
function test(){
    // 由于變量提升,輸出 undefined
    console.log(a);
    {
        var a = 1;
    }
    // 輸出 1
    console.log(a);
}
// 按照函數(shù)內(nèi)的注釋輸出
test();
// 報錯:Uncaught ReferenceError: a is not defined
console.log(a);

注:const 聲明的常量與 let 相同,也為塊級作用域。

參考

for 循環(huán)中的...問題,為什么改 var 為 let 就可以解決? - segmentfault

ES6之let(理解閉包)和const命令 - 博客園

「每日一題」JS 中的閉包是什么? - 知乎專欄

前端基礎(chǔ)進階(四):詳細圖解作用域鏈與閉包 - 簡書

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/81514.html

相關(guān)文章

  • JavaScript系列——JavaScript同步、異步、回調(diào)執(zhí)行順序之經(jīng)典閉包setTimeou

    摘要:同步異步回調(diào)傻傻分不清楚。分割線上面主要講了同步和回調(diào)執(zhí)行順序的問題,接著我就舉一個包含同步異步回調(diào)的例子。同步優(yōu)先回調(diào)內(nèi)部有個,第二個是一個回調(diào)回調(diào)墊底。異步也,輪到回調(diào)的孩子們回調(diào),出來執(zhí)行了。 同步、異步、回調(diào)?傻傻分不清楚。 大家注意了,教大家一道口訣: 同步優(yōu)先、異步靠邊、回調(diào)墊底(讀起來不順) 用公式表達就是: 同步 => 異步 => 回調(diào) 這口訣有什么用呢?用來對付面試的...

    lewif 評論0 收藏0
  • JavaScript系列——JavaScript同步、異步、回調(diào)執(zhí)行順序之經(jīng)典閉包setTimeou

    摘要:同步異步回調(diào)傻傻分不清楚。分割線上面主要講了同步和回調(diào)執(zhí)行順序的問題,接著我就舉一個包含同步異步回調(diào)的例子。同步優(yōu)先回調(diào)內(nèi)部有個,第二個是一個回調(diào)回調(diào)墊底。異步也,輪到回調(diào)的孩子們回調(diào),出來執(zhí)行了。 同步、異步、回調(diào)?傻傻分不清楚。 大家注意了,教大家一道口訣: 同步優(yōu)先、異步靠邊、回調(diào)墊底(讀起來不順) 用公式表達就是: 同步 => 異步 => 回調(diào) 這口訣有什么用呢?用來對付面試的...

    rockswang 評論0 收藏0
  • 前端er,你真的會用 async 嗎?

    摘要:異步函數(shù)是值通過事件循環(huán)異步執(zhí)行的函數(shù),它會通過一個隱式的返回其結(jié)果。 async 異步函數(shù) 不完全使用攻略 前言 現(xiàn)在已經(jīng)到 8012 年的尾聲了,前端各方面的技術(shù)發(fā)展也層出不窮,VueConf TO 2018 大會 也發(fā)布了 Vue 3.0的計劃。而在我們(我)的日常中也經(jīng)常用 Vue 來編寫一些項目。那么,就少不了 ES6 的登場了。那么話說回來,你真的會用 ES6 的 asyn...

    Jaden 評論0 收藏0
  • 4道經(jīng)典指針筆試題講解 ~

    摘要:結(jié)尾有關(guān)這四道經(jīng)典的指針筆試題講解就到此結(jié)束了,如果覺得文章對自己有所幫助,歡迎大家多多點贊收藏 ?前言 : 今天博主來講解4道經(jīng)典的指針筆試題,很多朋友沒有深刻理...

    tianren124 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<