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