摘要:聲明會(huì)組織對(duì)變量綁定和對(duì)自生值的修改,這意味著聲明并不會(huì)組織對(duì)變量成員的修改。循環(huán)中的塊級(jí)綁定在此處仍然可被訪問輸出的結(jié)果并不是預(yù)期的值而是是因?yàn)槁暶鲗?dǎo)致的變量的提升。全局塊級(jí)綁定與不同于的另一個(gè)方面是在全局作用域上的表現(xiàn)。
變量聲明一直是js工作中最微妙的一部分,它不像C語(yǔ)言一樣,變量總是在被它創(chuàng)建的時(shí)候聲明,js語(yǔ)言可以允許你在你需要聲明變量的時(shí)候進(jìn)行聲明。
var let const 之變量聲明
var 聲明與變量提升。
當(dāng)我們使用var關(guān)鍵字進(jìn)行變量聲明的時(shí)候,無(wú)論變量聲明的位置在哪里,都會(huì)被是為聲明于所在的函數(shù)的頂部(如果不在函數(shù)內(nèi)的話,則視為在全局作用域的頂部)這就是所謂的變量提升(hoisting)var提升如下:
function getValue(condition) { if (condition) { var value = "blue"; // 其他代碼 return value; } else { // value 在此處可訪問,值為 undefined return null; } // value 在此處可訪問,值為 undefined }
塊級(jí)聲明let
塊級(jí)聲明也就是讓所聲明的變量在指定的作用域外無(wú)法被訪問到,塊級(jí)作用域在如下情況下被創(chuàng)建在一個(gè)函數(shù)內(nèi)部,
在一個(gè)代碼塊(由一對(duì)花括號(hào)包裹)內(nèi)部
let聲明的語(yǔ)法和var聲明一致,由于let聲明不會(huì)將變量提升到函數(shù)頂部,因此我們需要手動(dòng)將let聲明放置到頂部,以便讓變量在整個(gè)代碼塊內(nèi)部可用。如下所示:
function getValue(condition) { if (condition) { let value = "blue"; // 其他代碼 return value; } else { // value 在此處不可用 return null; } // value 在此處不可用 }禁止重復(fù)標(biāo)識(shí)
如果一個(gè)標(biāo)識(shí)符已經(jīng)在代碼內(nèi)部被定義,重復(fù)進(jìn)行l(wèi)et聲明會(huì)報(bào)錯(cuò)
var a = 30; //報(bào)錯(cuò) let a = 30;a變量被聲明了兩次:一次使用 var ,另一次使用 let 。因?yàn)?let 不能在同一作用域內(nèi)重復(fù)聲明一個(gè)已有標(biāo)識(shí)符,此處的 let 聲明就會(huì)拋出錯(cuò)誤。另一方面,在嵌套的作用域內(nèi)使用 let 聲明一個(gè)同名的新變量,則不會(huì)拋出錯(cuò)誤,以下代碼對(duì)此進(jìn)行了演示:
var count = 30; // 不會(huì)拋出錯(cuò)誤 if (condition) { let count = 40; // 其他代碼 }這段代碼中不會(huì)拋錯(cuò),關(guān)鍵點(diǎn)在于let在同一級(jí)代碼塊中重復(fù)聲明會(huì)報(bào)錯(cuò) const常量聲明 在es6中可以使用const語(yǔ)法進(jìn)行聲明。使用const聲明的變量會(huì)被認(rèn)為是常量(constant),意味著他們的值在被設(shè)置完成后既不能再被改變。正因?yàn)槿绱耍械腸onst的變量都需要在聲明時(shí)進(jìn)行初始化,
// 有效的常量 const maxItems = 30; // 語(yǔ)法錯(cuò)誤:未進(jìn)行初始化 const name;maxItems 變量被初始化了,因此它的 const 聲明能正常起效。而 name 變量沒有被初始化,導(dǎo)致在試圖運(yùn)行這段代碼時(shí)拋出了錯(cuò)誤。const聲明會(huì)組織對(duì)變量綁定和對(duì)自生值的修改,這意味著const聲明并不會(huì)組織對(duì)變量成員的修改。例如:
const person = { name: "Nicholas" }; // 工作正常 person.name = "Greg"; // 拋出錯(cuò)誤 person = { name: "Greg" };const聲明和let聲明的對(duì)比
首先他們都是塊級(jí)聲明,這就意味著常量在聲明它們的語(yǔ)句塊外是無(wú)法被訪問的,并且聲明也不會(huì)被提升,示例如下:
if (condition) { const maxItems = 5; // 其他代碼 } // maxItems 在此處無(wú)法訪問
它們?cè)诮y(tǒng)一級(jí)作用域中重復(fù)聲明時(shí)會(huì)導(dǎo)致拋出錯(cuò)誤
暫時(shí)性死區(qū) 當(dāng)我們使用let或者const 進(jìn)行聲明的時(shí)候,在到達(dá)聲明處之前都是無(wú)法訪問的,如果我們?cè)噲D訪問會(huì)導(dǎo)致一個(gè)引用錯(cuò)誤。出項(xiàng)這個(gè)問題是因?yàn)闀簳r(shí)性死區(qū) 當(dāng)JS 引擎檢視接下來(lái)的代碼塊并發(fā)現(xiàn)變量聲明時(shí),它會(huì)在面對(duì) var 的情況下將聲明提升到函數(shù)或全局作用域的頂部,而面對(duì) let 或 const 時(shí)會(huì)將聲明放在暫時(shí)性死區(qū)內(nèi)。任何在暫時(shí)性死區(qū)內(nèi)訪問變量的企圖都會(huì)導(dǎo)致“運(yùn)行時(shí)”錯(cuò)誤(runtime error)。只有執(zhí)行到變量的聲明語(yǔ)句時(shí),該變量才會(huì)從暫時(shí)性死區(qū)內(nèi)被移除并可以安全使用。 循環(huán)中的塊級(jí)綁定for (var i = 0; i < 10; i++) { process(items[i]); } // i 在此處仍然可被訪問 console.log(i); // 10
輸出的結(jié)果并不是預(yù)期的值而是10;是因?yàn)関ar聲明導(dǎo)致的變量的提升。聰明的你肯定會(huì)想到使用塊級(jí)綁定來(lái)進(jìn)行變量聲明
for (let i = 0; i < 10; i++) { process(items[i]); } console.log(i);
i在此處是不是會(huì)正常輸出呢,其實(shí)不會(huì),在這個(gè)例子中會(huì)導(dǎo)致報(bào)錯(cuò),為什么呢?因?yàn)閕在此處不可訪問。本例中的變量 i 僅在 for 循環(huán)內(nèi)部可用,一旦循環(huán)結(jié)束,該變量在任意位置都不可訪問。
我們?cè)趤?lái)看看一下代碼
var funcs = []; for (var i = 0; i < 10; i++) { funcs.push(function() { console.log(i); }); } funcs.forEach(function(func) { func(); // 輸出數(shù)值 "10" 十次 });
你原本可能預(yù)期這段代碼會(huì)輸出 0 到 9 的數(shù)值,但它卻在同一行將數(shù)值 10 輸出了十次。這是
因?yàn)樽兞?i 在循環(huán)的每次迭代中都被共享了,意味著循環(huán)內(nèi)創(chuàng)建的那些函數(shù)都擁有對(duì)于同一
變量的引用。在循環(huán)結(jié)束后,變量 i 的值會(huì)是 10 ,因此當(dāng) console.log(i) 被調(diào)用時(shí),
每次都打印出 10 。
為了修正這個(gè)問題,開發(fā)者在循環(huán)內(nèi)使用立即調(diào)用函數(shù)表達(dá)式(IIFEs),以便在每次迭代中
強(qiáng)制創(chuàng)建變量的一個(gè)新副本,示例如下:
var funcs = []; for (var i = 0; i < 10; i++) { funcs.push((function(value) { return function() { console.log(value); } }(i))); } funcs.forEach(function(func) { func(); // 從 0 到 9 依次輸出 });循環(huán)內(nèi)的 let 聲明
let 聲明通過有效模仿上例中 IIFE 的作用而簡(jiǎn)化了循環(huán)。在每次迭代中,都會(huì)創(chuàng)建一個(gè)新的
同名變量并對(duì)其進(jìn)行初始化。這意味著你可以完全省略 IIFE 而獲得預(yù)期的結(jié)果,就像這樣
var funcs = []; for (let i = 0; i < 10; i++) { funcs.push(function() { console.log(i); }); } funcs.forEach(function(func) { func(); // 從 0 到 9 依次輸出 })
我們是否會(huì)想到這個(gè)問題:為什么同樣的代碼使用let聲明會(huì)導(dǎo)致不一樣的結(jié)果呢?
在循環(huán)中l(wèi)et聲明每次都創(chuàng)建了一個(gè)新的i變量,因此在循環(huán)內(nèi)部創(chuàng)建的函數(shù)獲得了各自的i副本,而每個(gè)i副本的值都會(huì)在每次的循環(huán)迭代聲明變量的時(shí)候確定了
var funcs = [], object = { a: true, b: true, c: true }; for (let key in object) { funcs.push(function() { console.log(key); }); } funcs.forEach(function(func) { func(); // 依次輸出 "a"、 "b"、 "c" });
本例中的 for-in 循環(huán)體現(xiàn)出了與 for 循環(huán)相同的行為。每次循環(huán),一個(gè)新的 key 變量綁
定就被創(chuàng)建,因此每個(gè)函數(shù)都能夠擁有它自身的 key 變量副本,結(jié)果每個(gè)函數(shù)都輸出了一個(gè)
不同的值。而如果使用 var 來(lái)聲明 key ,則所有函數(shù)都只會(huì)輸出 "c" 。
let 聲明在循環(huán)內(nèi)部的行為是在規(guī)范中特別定義的,而與不提升變
量聲明的特征沒有必然聯(lián)系。事實(shí)上,在早期 let 的實(shí)現(xiàn)中并沒有這種行為,它是后來(lái)
才添加的。
雖然es6沒有明確的規(guī)范我們不能在for循環(huán)中使用const聲明,然而它會(huì)根據(jù)循環(huán)方式的不同而有不同的行為,我們可以在初始化時(shí)使用const,但是當(dāng)循環(huán)試圖改變變量的值的時(shí)候會(huì)拋出錯(cuò)誤,例如:
var funcs = []; // 在一次迭代后拋出錯(cuò)誤 for (const i = 0; i < 10; i++) { funcs.push(function() { console.log(i); }); }
在此代碼中, i 被聲明為一個(gè)常量。循環(huán)的第一次迭代成功執(zhí)行,此時(shí) i 的值為 0 。在
i++ 執(zhí)行時(shí),一個(gè)錯(cuò)誤會(huì)被拋出,因?yàn)樵撜Z(yǔ)句試圖更改常量的值。因此,在循環(huán)中你只能使
用 const 來(lái)聲明一個(gè)不會(huì)被更改的變量
而另一方面, const 變量在 for-in 或 for-of 循環(huán)中使用時(shí),與 let 變量效果相同。因
此下面代碼不會(huì)導(dǎo)致出錯(cuò):
var funcs = [], object = { a: true, b: true, c: true }; // 不會(huì)導(dǎo)致錯(cuò)誤 for (const key in object) { funcs.push(function() { console.log(key); }); } funcs.forEach(function(func) { func(); // 依次輸出 "a"、 "b"、 "c" });
這段代碼與“循環(huán)內(nèi)的 let 聲明”小節(jié)的第二個(gè)例子幾乎完全一樣,唯一的區(qū)別是 key 的值在
循環(huán)內(nèi)不能被更改。 const 能夠在 for-in 與 for-of 循環(huán)內(nèi)工作,是因?yàn)檠h(huán)為每次迭
代創(chuàng)建了一個(gè)新的變量綁定,而不是試圖去修改已綁定的變量的值(就像使用了 for 而不是
for-in 的上個(gè)例子那樣)。
let 與 const 不同于 var 的另一個(gè)方面是在全局作用域上的表現(xiàn)。當(dāng)在全局作用域上使 用 var 時(shí),它會(huì)創(chuàng)建一個(gè)新的全局變量,并成為全局對(duì)象(在瀏覽器中是 window )的一 個(gè)屬性。總結(jié) let和const塊級(jí)作用域的引入,能夠使我們減少很多無(wú)心的錯(cuò)誤,它們的一個(gè)副作用,是不能在變量聲明位置之前訪問它們 塊級(jí)綁定當(dāng)前的最佳實(shí)踐就是:在默認(rèn)情況下使用 const ,而只在你知道變量值需要被更改的情況下才使用 let 。這在代碼中能確?;緦哟蔚牟豢勺冃?,有助于防止某些類型的錯(cuò)誤。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/103124.html
摘要:眾所周知,中的聲明存在變量提升機(jī)制,因此引用了塊級(jí)作用域來(lái)強(qiáng)化對(duì)變量生命周期的控制聲明不會(huì)被提升,有幾個(gè)需要注意的點(diǎn)不能被重復(fù)聲明假設(shè)作用域中已經(jīng)存在某個(gè)標(biāo)識(shí)符無(wú)論該標(biāo)識(shí)符是通過聲明還是變量聲明,此時(shí)再使用或關(guān)鍵定聲明會(huì)拋錯(cuò)此處則會(huì)拋出錯(cuò)誤 眾所周知,js中的var聲明存在變量提升機(jī)制,因此ESMAScript 6引用了塊級(jí)作用域來(lái)強(qiáng)化對(duì)變量生命周期的控制let const 聲明不會(huì)被...
摘要:聲明變量不存在變量提升。臨時(shí)死區(qū),而且不能在聲明之前訪問它。禁止重復(fù)聲明相同的變量,否則報(bào)錯(cuò)。不存在變量提升,一旦執(zhí)行快外就會(huì)立即銷毀。聲明不允許修改綁定,但允許修改值,也就是說用創(chuàng)建對(duì)象后,可以修改該對(duì)象的屬性值。 知識(shí)點(diǎn) var 聲明變量: 1、存在變量提升,實(shí)際上var無(wú)論在哪里聲明,都會(huì)被當(dāng)做當(dāng)前的作用域頂部聲明變量。 2、可以重復(fù)聲明,后聲明的變量會(huì)覆蓋前聲明的變量。 let...
摘要:塊級(jí)作用域存在于函數(shù)內(nèi)部塊中字符和之間的區(qū)域和塊級(jí)聲明用于聲明在指定塊的作用域之外無(wú)法訪問的變量。和都是塊級(jí)聲明的一種。值得一提的是聲明不允許修改綁定,但允許修改值。這意味著當(dāng)用聲明對(duì)象時(shí)沒有問題報(bào)錯(cuò)臨時(shí)死區(qū)臨時(shí)死區(qū),簡(jiǎn)寫為。 塊級(jí)作用域的出現(xiàn) 通過 var 聲明的變量存在變量提升的特性: if (condition) { var value = 1; } console.lo...
摘要:聲明一個(gè)只讀的常量。的作用域與命令相同只在聲明所在的塊級(jí)作用域內(nèi)有效。這在語(yǔ)法上,稱為暫時(shí)性死區(qū),簡(jiǎn)稱。暫時(shí)性死區(qū)也意味著不再是一個(gè)百分之百安全的操作。重復(fù)聲明是允許在相同作用域內(nèi)重復(fù)聲明同一個(gè)變量的,而與不允許這一現(xiàn)象。 轉(zhuǎn)載自阮一峰老師的ES6入門,稍有修改 1.基本概念MDN var聲明了一個(gè)變量,并且可以同時(shí)初始化該變量。let語(yǔ)句聲明一個(gè)塊級(jí)作用域的本地變量,并且可選的賦予...
閱讀 844·2021-11-09 09:47
閱讀 1651·2019-08-30 15:44
閱讀 1193·2019-08-26 13:46
閱讀 2175·2019-08-26 13:41
閱讀 1363·2019-08-26 13:32
閱讀 3846·2019-08-26 10:35
閱讀 3593·2019-08-23 17:16
閱讀 515·2019-08-23 17:07