摘要:規(guī)范對(duì)其是這樣進(jìn)行的描述的。聲明定義了在正在運(yùn)行的執(zhí)行上下文作用域內(nèi)的變量環(huán)境中的變量。在執(zhí)行時(shí),由帶有的定義的變量被賦其設(shè)定項(xiàng)的的值。由于變量已經(jīng)被聲明,是可訪問(wèn)的,因此會(huì)打印出正確的結(jié)果。
你想在在變量聲明之前就使用變量?以后再也別這樣做了。
新的聲明方式(let,const)較之之前的聲明方式(var),還有一個(gè)區(qū)別,就是新的方式不允許在變量聲明之前就使用該變量,但是var是可以得。請(qǐng)看下面的代碼,下面這個(gè)代碼是可以正常運(yùn)行的:
function func() { console.log(localVariable); // undefined var localVariable = 5; console.log(localVariable); // 5 } func();
但是這種卻不可以
function func() { console.log(localVariable); // ReferenceError: localVariable is not defined let localVariable = 10; console.log(localVariable); // 10 } func();
等下,我們上一章曾經(jīng)介紹了一個(gè)叫“提升”的概念,它會(huì)吧所有的變量定義在作用域的最前面。這是否意味著如果我不在實(shí)際的定義之前使用變量,然后就不會(huì)有提升了呢?答案是否定的。提升依然會(huì)有,并且適用于所有類(lèi)型的變量類(lèi)型。但是const和let卻不是這樣的。
首先,我們看一下var關(guān)鍵字是怎么工作的。規(guī)范對(duì)其是這樣進(jìn)行的描述的。
var聲明定義了在正在運(yùn)行的執(zhí)行上下文(running execution
context)作用域內(nèi)的變量環(huán)境(VariableEnvironment中)的變量。var變量在當(dāng)包含的詞法環(huán)境(Lexical
Environment)初始化時(shí)被創(chuàng)建,在創(chuàng)建的時(shí)候被賦值為undefined。[...]
在執(zhí)行VariableDeclaration時(shí),由帶有Initializer的VariableDeclaration定義的變量被賦其設(shè)定項(xiàng)的Initializer"s
AssignmentExpression的值。
規(guī)范中有許多的細(xì)節(jié),讓我們簡(jiǎn)單的來(lái)看一下:
當(dāng)你進(jìn)入到一個(gè)作用域中,在內(nèi)部被定義的所有的變量都會(huì)被創(chuàng)建。
所有存在的變量,都可以被訪問(wèn),并且會(huì)把undefined賦值給該變量。
當(dāng)代碼(執(zhí)行時(shí))到達(dá)初始化時(shí),會(huì)被分配給一個(gè)實(shí)際的值。
我們來(lái)看一下規(guī)范中對(duì)let和const的表述:
let和const聲明是定義在當(dāng)前執(zhí)行上下文作用域中的詞法環(huán)境中的變量。當(dāng)包含的詞法環(huán)境被初始化的時(shí)候,變量被創(chuàng)建。但是在變量的詞法綁定時(shí)被計(jì)算之前是不允許通過(guò)任何方式來(lái)訪問(wèn)的。當(dāng)詞法綁定計(jì)算時(shí)而不是在變量被創(chuàng)建的時(shí)候,由詞法綁定定義的變量的初始值被被賦予賦值表達(dá)式的值(也就是“=”右邊的表達(dá)式)。當(dāng)詞法綁定被計(jì)算的時(shí)候,如果let聲明中沒(méi)有初始化的值的時(shí)候(也就是“l(fā)et
a;”這樣的形式),會(huì)被賦值為undefined。
簡(jiǎn)單來(lái)說(shuō):
如果你進(jìn)入到了指定的作用域中,它里面定義的所有的變量都會(huì)被初始化,這一點(diǎn)和var很像。
這里有一個(gè)不同點(diǎn):像var一樣,所有的變量都會(huì)存在,但是他們目前還不能被訪問(wèn)(里面沒(méi)有值,甚至是undefined)。
如果let變量在相同的地方被定義和初始化,他們會(huì)被賦予合適的值,反之,變量就是undefined。const變量必須在定義的時(shí)候初始化。
我們來(lái)看一些相關(guān)的例子。
臨時(shí)死區(qū)實(shí)際上,這種描述引出了我們的另一個(gè)定義。他很讓人可怕,因?yàn)樗校号R時(shí)死區(qū)(TDZ)。這個(gè)屬于明確了一個(gè)我們無(wú)法訪問(wèn)我們的變量的代碼的區(qū)域。我們來(lái)看一下下面的代碼和相關(guān)聯(lián)的注釋?zhuān)瑏?lái)簡(jiǎn)單的解釋一下TDZ是什么。
function func() { // Start of TDZ for deadVariable // we can still do something here, just our deadVariable is not available yet const exampleVariable = 5; console.log(exampleVariable); // 5 // End of TDZ for deadVariable let deadVariable = 10; console.log(deadVariable); // 10 } func();
有一件事情值得去提醒。就是對(duì)于名字的建議,這是一個(gè)臨時(shí)死區(qū),意思這個(gè)區(qū)域是由時(shí)間定義的,而不是位置。因此當(dāng)運(yùn)行代碼的時(shí)候,你的聲明在被JS解析器解析之前是不能被訪問(wèn)的。因此你把使用的變量的位置放在哪里并不重要,只要是在聲明執(zhí)行后訪問(wèn)該變量就可以。所以看下面的代碼:
function func() { return deadOrAlive; } let deadOrAlive = "alive!" console.log(func()); // alive!
這是運(yùn)行代碼的步驟:
函數(shù)被聲明
變量deadOrAlive被聲明,并且初始化了一個(gè)值“alive”
現(xiàn)在我們調(diào)用我們的函數(shù)。
由于變量deadOrAlive已經(jīng)被聲明,是可訪問(wèn)的,因此會(huì)打印出正確的結(jié)果 “alive”。
但是下面的例子卻會(huì)報(bào)錯(cuò),思考一下原因。
function func() { return deadOrAlive; } console.log(func()); // ReferenceError: deadOrAlive is not defined let deadOrAlive = "dead!"
所以TDZ是一個(gè)避免因先使用后聲明而導(dǎo)致的一些詭異的bug而出現(xiàn)的一個(gè)很好機(jī)制(具體看“提升”相關(guān)內(nèi)容)。我們不需要去額外做什么事情,就是記住永遠(yuǎn)不要在變量聲明之前使用這個(gè)變量。即使我們這樣做了,我們也會(huì)得到一個(gè)很好的報(bào)錯(cuò)信息。只有一個(gè)條件-你必須使用let或者是const來(lái)替換掉var。
雙定義var和let,const的另一個(gè)區(qū)別是 - 后者僅僅可以被定義一次。而對(duì)于var的話,如果被同時(shí)定義多次,程序也依然會(huì)很好的運(yùn)行。
var doubledVariable = 5; var doubledVariable = 6; console.log(doubledVariable); // 6
但是現(xiàn)在,當(dāng)你用let和const來(lái)做同樣的事情,就會(huì)得到一個(gè)語(yǔ)法錯(cuò)誤:
let doubledVariable = 5; let doubledVariable = 6; // SyntaxError: Identifier "doubledVariable" has already been declared
但是,在嵌套的塊級(jí)作用域中,使用相同名字的變量依然會(huì)很好的工作的,這個(gè)我想大家已經(jīng)清楚了,就不用過(guò)多解釋了吧。
let doubledVariable = 5; if (true) { let doubledVariable = 6; console.log(doubledVariable); // 6 } console.log(doubledVariable); // 5
不能重復(fù)定義這個(gè)功能實(shí)際上是很有用的,可以組織很多bug的發(fā)生。比如說(shuō)你曾經(jīng)在一個(gè)函數(shù)內(nèi),在不同地方用var定義了多個(gè)相同名稱(chēng)的變量,此時(shí)之前定義的變量可能會(huì)被覆蓋,這樣對(duì)于代碼來(lái)說(shuō)無(wú)疑是一個(gè)隱患,也就是因?yàn)檫@樣,這個(gè)特性實(shí)際上是一個(gè)簡(jiǎn)單的,開(kāi)箱即用的解決方案。
總結(jié)總結(jié)一下,在ES6中有兩種新方法來(lái)聲明變量:通過(guò)let和const關(guān)鍵字,除此之外,兩者都是塊級(jí)作用域,并且在聲明之前不能訪問(wèn)該變量。與之前的var相比是一個(gè)主要的升級(jí)。并且會(huì)消除你很多的困擾。我提出了幾個(gè)例子,可能會(huì)幫助你節(jié)省了不少調(diào)試的時(shí)間,但是還有更多。如果你感興趣的話,可以在網(wǎng)上簡(jiǎn)單的搜索一下。很久之前,我個(gè)人曾建議停止使用var關(guān)鍵字,所以現(xiàn)在我的代碼里充滿了let和const。我建議你也是這樣,在以后當(dāng)你想改變變量的值,就使用let和const。不要再使用var了。
本文翻譯自:
https://blog.pragmatists.com/...
本文轉(zhuǎn)載自:http://www.lht.ren/article/16/
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/101729.html
摘要:引擎對(duì)堆內(nèi)存中的對(duì)象進(jìn)行分代管理新生代存活周期較短的對(duì)象,如臨時(shí)變量字符串等。內(nèi)存泄漏對(duì)于持續(xù)運(yùn)行的服務(wù)進(jìn)程,必須及時(shí)釋放不再用到的內(nèi)存。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開(kāi)始前端進(jìn)階的第一期,本周的主題是調(diào)用堆棧,今天是第4天。 本計(jì)劃一共28期,每期重點(diǎn)攻克一個(gè)面試重難點(diǎn),如果你還不了解本進(jìn)階計(jì)劃...
摘要:當(dāng)我們的視圖和數(shù)據(jù)任何一方發(fā)生變化的時(shí)候,我們希望能夠通知對(duì)方也更新,這就是所謂的數(shù)據(jù)雙向綁定。返回值返回傳入函數(shù)的對(duì)象,即第一個(gè)參數(shù)該方法重點(diǎn)是描述,對(duì)象里目前存在的屬性描述符有兩種主要形式數(shù)據(jù)描述符和存取描述符。 前言 談起當(dāng)前前端最熱門(mén)的 js 框架,必少不了 Vue、React、Angular,對(duì)于大多數(shù)人來(lái)說(shuō),我們更多的是在使用框架,對(duì)于框架解決痛點(diǎn)背后使用的基本原理往往關(guān)注...
摘要:首次運(yùn)行代碼時(shí),會(huì)創(chuàng)建一個(gè)全局執(zhí)行上下文并到當(dāng)前的執(zhí)行棧中。執(zhí)行上下文的創(chuàng)建執(zhí)行上下文分兩個(gè)階段創(chuàng)建創(chuàng)建階段執(zhí)行階段創(chuàng)建階段確定的值,也被稱(chēng)為。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開(kāi)始前端進(jìn)階的第一期,本周的主題是調(diào)用堆棧,,今天是第一天 本計(jì)劃一共28期,每期重點(diǎn)攻克一個(gè)面試重難點(diǎn),如果你還不了解本進(jìn)...
摘要:閉包面試題解由于作用域鏈機(jī)制的影響,閉包只能取得內(nèi)部函數(shù)的最后一個(gè)值,這引起的一個(gè)副作用就是如果內(nèi)部函數(shù)在一個(gè)循環(huán)中,那么變量的值始終為最后一個(gè)值。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開(kāi)始前端進(jìn)階的第二期,本周的主題是作用域閉包,今天是第8天。 本計(jì)劃一共28期,每期重點(diǎn)攻克一個(gè)面試重難點(diǎn),如果你還不了...
摘要:接著上一篇文章深入了解一的處理步驟的三個(gè)主要處理步驟分別是解析,轉(zhuǎn)換,生成。模塊是的代碼生成器,它讀取并將其轉(zhuǎn)換為代碼和源碼映射抽象語(yǔ)法樹(shù)抽象語(yǔ)法樹(shù)在以上三個(gè)神器中都出現(xiàn)過(guò),所以對(duì)于編譯器來(lái)說(shuō)至關(guān)重要。 接著上一篇文章《深入了解babel(一)》 Babel 的處理步驟 Babel 的三個(gè)主要處理步驟分別是: 解析(parse),轉(zhuǎn)換(transform),生成(generate)。對(duì)...
閱讀 3018·2023-04-25 20:22
閱讀 3335·2019-08-30 11:14
閱讀 2590·2019-08-29 13:03
閱讀 3178·2019-08-26 13:47
閱讀 3218·2019-08-26 10:22
閱讀 1263·2019-08-23 18:26
閱讀 609·2019-08-23 17:16
閱讀 1908·2019-08-23 17:01