真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

JavaScript變量or循環(huán)中的var和let怎么使用

這篇“JavaScript變量or循環(huán)中的var和let怎么使用”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“JavaScript變量or循環(huán)中的var和let怎么使用”文章吧。

10年積累的網(wǎng)站設(shè)計、成都做網(wǎng)站經(jīng)驗,可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認識你,你也不認識我。但先網(wǎng)站設(shè)計后付款的網(wǎng)站建設(shè)流程,更有西峽免費網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。

在for循環(huán)中使用var聲明初始化帶來的問題

// 一道經(jīng)典面試題:
var funcs = [];
for (var i = 0; i < 3; i++) {
  funcs[i] = function() {
    console.log("My value: " + i)
  };
}
for (var j = 0; j < 3; j++) {
  funcs[j]();
}
/*
輸出結(jié)果:
> My value: 3
> My value: 3
> My value: 3
*/

會出現(xiàn)這種現(xiàn)象的原因就是:

  • var聲明的作用域是函數(shù)作用域而不是塊級作用域,因此在for循環(huán)的循環(huán)體之外依然能訪問到在初始化for循環(huán)時定義的var變量。

  • 且在循環(huán)結(jié)束后訪問時,訪問到的var變量是已經(jīng)完成循環(huán)后的值。

解決方法

使用閉包

ES5時代的解決辦法就是通過IIFE創(chuàng)建一個閉包,把變量在函數(shù)體內(nèi)保存起來,再執(zhí)行函數(shù)時就不會去訪問外層的var變量了。

var funcs = [];
for (var i = 0; i < 3; i++) {
    // 1. 閉包
    funcs[i] = (function (i) {
        return function () {
            console.log("My value: " + i);
        };
    })(i);
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}

使用let變量初始化

let聲明是塊級作用域,循環(huán)體內(nèi)的變量不會泄露到塊語句之外。

因此在循環(huán)結(jié)束后再去訪問變量i時,沒有外層作用域變量的干擾,訪問到的自然就是函數(shù)體內(nèi)保存下來的變量值。

var funcs = [];
// 2. let
for (let i = 0; i < 3; i++) {
  funcs[i] = function() {
    console.log("My value: " + i);
  };
}
for (var j = 0; j < 3; j++) {
  funcs[j]();
}

從這里也可以看出,使用var來初始化for循環(huán)本身就是違反直覺的。

用來初始化for循環(huán)的變量理應(yīng)是for循環(huán)的局部變量,在循環(huán)結(jié)束以后這個變量就應(yīng)該沒有意義了才對。

但是如果使用var來初始化,由于var聲明的變量的作用域是函數(shù)作用域,這個初始化變量就和for循環(huán)處于同一作用域了,不受for循環(huán)的限制。

本應(yīng)是for循環(huán)的局部變量,卻暴露在了和for循環(huán)同層的作用域,且變量值已經(jīng)被循環(huán)次數(shù)改變,自然會影響循環(huán)結(jié)束后其他代碼對該變量的訪問。

而如果使用let來初始化for循環(huán),就不會有這個困擾了,因為let聲明的作用域是塊級作用域,這個初始化變量會如愿成為for循環(huán)的局部變量。

for循環(huán)怎么處理用let和var聲明的初始化變量?

先上結(jié)論:

  • 用var初始化時,for循環(huán)會直接使用創(chuàng)建的var初始化變量;

  • 用let初始化時,圓括號會自成一個作用域,for循環(huán)會將圓括號內(nèi)的變量值往循環(huán)體內(nèi)傳遞。

首先看第一個結(jié)論,規(guī)范是這么說的:

JavaScript變量or循環(huán)中的var和let怎么使用

可以看到,規(guī)范對于var初始化變量沒有什么特別的處理,直接就拿來用了。 此時這個變量就是個普通的var變量,和for循環(huán)處于同一作用域。

我們用代碼來佐證一下:

var funcs = [];
for (var i = 0; i < 3; i++) {
    // ?。?!重復(fù)聲明了一個同名的var變量
    var i = 5;
    console.log("My value: " + i);
}
/*
只會輸出一次:
> My value: 5
*/

var可以重復(fù)聲明且值會覆蓋,因此在循環(huán)體內(nèi)再聲明一個var i = 5,循環(huán)變量被作沒了,會直接跳出for循環(huán)。

var funcs = [];
for (var i = 0; i < 3; i++) {
    // 用let聲明了一個和循環(huán)變量同名的變量
    let i = 5;
    console.log("My value: " + i);
}
/*
一共輸出了3次:
> My value: 5
> My value: 5
> My value: 5
*/

初始化var變量在函數(shù)作用域,循環(huán)體內(nèi)的let變量在塊作用域,循環(huán)體內(nèi)優(yōu)先訪問塊作用域里的let變量,因此循環(huán)體內(nèi)的i值會被覆蓋。

又由于var變量實際上處于let變量的外層作用域,因此let變量沒有重復(fù)聲明,不會報錯;var變量也會如期完成自己作為循環(huán)變量的使命。

再看第二個結(jié)論,同樣是先看規(guī)范:

很明顯可以發(fā)現(xiàn),使用let來初始化會比使用var多了一個叫perIterationLets的東西。

perIterationLets是什么?

從規(guī)范上可以看到,perIterationLets來源于LexicalDeclaration(詞法聲明)里的boundNames。

而這個LexicalDeclaration(詞法聲明),其實就是我們用來初始化的let聲明。

可以理解為,如果我們用let聲明來初始化for循環(huán),for循環(huán)內(nèi)部不會像直接使用var變量一樣來直接使用let變量,而是會先把let變量收集起來,以某種形式轉(zhuǎn)換為perIterationLets,再傳遞給循環(huán)體。

perIterationLets被用來做什么的?

從規(guī)范上可以看到,我們的let變量以perIterationLets的身份,作為參數(shù)被傳進了ForBodyEvaluation,也就是循環(huán)體里。

在循環(huán)體里,perIterationLets只做了一件事情,那就是作為CreatePerIterationEnvironment的參數(shù):

從字面上理解,CreatePerIterationEnvironment意思就是每次循環(huán)都要創(chuàng)建的環(huán)境

要注意,這個環(huán)境不是{...}里的那些執(zhí)行語句所處的環(huán)境。 {...}里的執(zhí)行語句是statement,在規(guī)范里可以看到,stmt有自己的事情要做。

這個環(huán)境是屬于圓括號的作用域,也就是我們定義的let初始化變量所在的作用域。

再看看每次循環(huán)都要創(chuàng)建的環(huán)境被用來干嘛了:

逐步分析一下方法:CreatePerIterationEnvironment這個

  • 首先,把當前執(zhí)行上下文的詞法環(huán)境保存下來,作為lastIterationEnv(上一次循環(huán)時的環(huán)境)

  • 創(chuàng)建一個和lastIterationEnv同級的新作用域,作為thisIterationEnv(本次循環(huán)的環(huán)境);

  • 遍歷我們定義的let初始化變量,也就是perIterationLets,在thisIterationEnv(本次循環(huán)的環(huán)境)里創(chuàng)建一個同名的可變綁定,找到它們在lastIterationEnv(上一次循環(huán)時的環(huán)境)里的終值,作為這個同名綁定的初始值;

  • 最后,將thisIterationEnv(本次循環(huán)的環(huán)境)交還給執(zhí)行上下文。

簡而言之就是,for循環(huán)會在迭代之前創(chuàng)建一個和初始化變量同名的變量,并使用之前迭代的終值將這個變量初始化以后,再交還給執(zhí)行上下文。

用偽代碼理解一下這個過程就是:

到這里又有一個問題,既然把圓括號內(nèi)的變量向循環(huán)體里傳遞了,那如果在循環(huán)體里又重復(fù)聲明了一個同名變量,算不算重復(fù)聲明,會不會報錯?

答案是不會。

因為CreatePerIterationEnvironment在執(zhí)行時,在新環(huán)境里創(chuàng)建的是一個可變的綁定,因此如果在循環(huán)體內(nèi)重復(fù)聲明一個名字為i的變量,只是會影響循環(huán)體內(nèi)執(zhí)行語句對i值的訪問。

var funcs = [];
for (let i = 0; i < 3; i++) {
    // ?。?!用let聲明了一個和循環(huán)變量同名的變量
    let i = 5;
    console.log("My value: " + i);
}
/*
一共輸出了3次:
> My value: 5
> My value: 5
> My value: 5
*/

總結(jié)

在for循環(huán)中使用var聲明來初始化的話,循環(huán)變量會暴露在和for循環(huán)同一作用域下,導(dǎo)致循環(huán)結(jié)束后還能訪問到循環(huán)變量,且訪問到的變量值是經(jīng)過循環(huán)迭代后的值。

解決這個問題的方法如下:

  • 使用閉包將循環(huán)變量的值作為局部變量保存起來;

  • 使用ES6的let聲明,將循環(huán)變量的作用域限制在for循環(huán)內(nèi)部,初始化變量始終是for循環(huán)的局部變量,不能在外界被訪問到。

for循環(huán)是怎么處理用let和var聲明的初始化變量的?

  • 用var初始化時,for循環(huán)會直接使用創(chuàng)建的var初始化變量;

  • 用let初始化時,圓括號會自成一個作用域,for循環(huán)會將圓括號內(nèi)的變量值往循環(huán)體內(nèi)傳遞。

以上就是關(guān)于“JavaScript變量or循環(huán)中的var和let怎么使用”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


名稱欄目:JavaScript變量or循環(huán)中的var和let怎么使用
轉(zhuǎn)載注明:http://weahome.cn/article/pisehh.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部