簡體   English   中英

使用var與let / const進行塊級變量重新聲明

[英]Block-level variable redeclaration with var vs. let/const

第1部分

鑒於這個例子:

var number = 10
{
   var number = 42
}
console.log(number) // 42

為什么第4行沒有拋出Uncaught SyntaxError: Identifier 'number' has already been declared 由於塊作用域,它與let / const一起使用(雖然輸出當然是10而不是42 ),但它如何與var

第2部分

將此與以下相比較,它與var

var number = 10
var number = 42
console.log(number) // 42

但是不要let

let number = 10
let number = 42 // SyntaxError
console.log(number)

為什么var被賦予“免費通行證”? 是否與使用var時重新分配給窗口對象的number屬性有關?

即使在嚴格模式下 ,您也可以在JavaScript中重新聲明var變量。

var聲明的變量的范圍是它的當前執行上下文 ,它是封閉函數,或者對於在任何函數外部聲明的變量,是全局的。 如果重新聲明JavaScript變量,它將不會丟失其值。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting

 'use strict' var someVar = 'Hello'; var someVar = 2 + 2; console.log(someVar); 

為什么第4行沒有拋出Uncaught SyntaxError: Identifier 'number' has already been declared

正如Sébastien已經提到的 ,用var聲明的變量在當前執行上下文中聲明,並且可以重新聲明。 可以將執行上下文的概念與框進行比較。 根據ECMAScript語言規范第8.3節

8.3執行上下文

執行上下文是一種規范設備,用於跟蹤ECMAScript實現對代碼的運行時評估。 在任何時間點,每個代理程序最多只有一個執行上下文實際執行代碼。 這稱為代理程序的運行執行上下文

[...]

ECMAScript代碼的執行上下文具有表22中列出的其他狀態組件。

表22:ECMAScript代碼執行上下文的附加狀態組件
\n  組件目的\n\n  
  
  
  
\n\n LexicalEnvironment標識用於解析此執行上下文中的代碼所做的標識符引用的詞法環境。\n VariableEnvironment標識其EnvironmentRecord包含由此執行上下文中的VariableStatements創建的綁定的詞法環境。\n

因此,每次編寫JavaScript代碼時,它都被分成幾個小的“盒子”,稱為執行上下文,只要解釋器遇到一個新的語法結構(如塊,函數聲明等)就會創建在每個框中,都有許多組件,但特別是LexicalEnvironmentVariableEnvironment 這些都是父執行上下文“框”內的“迷你框”,它們保存對代碼可以訪問的當前執行上下文中聲明的變量的引用。 LexicalEnvironment指的是用letconst聲明的變量。 VariableEnvironment是指使用var創建的變量。

現在看第13.3.2節

13.3.2變量聲明

注意var語句聲明了作用於正在運行的執行上下文的VariableEnvironment的變量。 Var變量在實例化包含詞法環境時創建,並在創建時初始化為undefined 在任何VariableEnvironment的范圍內,常見的BindingIdentifier可能出現在多個VariableDeclaration中,但這些聲明共同只定義一個變量。

引用注釋的最后一部分說明了為什么可以多次聲明var的原因。 每次解釋器遇到一個函數時,都會創建一個新的VariableEnvironment ,因為var是函數作用域的,如果你在全局作用域中,則有一個全局的VariableEnvironment 在您的情況下,您已在全局范圍內聲明了number ,因為{ … }是一個塊,而不是一個函數,但它們共同只定義一number 因此,您的代碼實際執行與此相同:

var number = 10 //declared once
{
  number = 42 //since { … } does not create a new VariableEnvironment, number is the same 
              //variable as the one outside the block. Thus, the two declarations only define
              //number once and every redeclaraction is essentially reassignment.
}
console.log(number) //42

正如你所說, letconst是塊范圍的。 它們不會拋出錯誤,因為{ … }會創建一個新塊。

為什么var被賦予“免費通行證”? 是否與使用var時重新分配給窗口對象的number屬性有關?

如前所述, var可以在VariableEnvironment多次出現 - 但對於letconst ,同樣不會出現真正的問題。 作為BERGI提到 ,ECMAScript的作者沒有意識到的挫折和具有這樣的壞聲明符的怪癖var直到很久以后,並改變var的行為會導致整個網絡崩潰,因為向后兼容性是ECMAScript中的一個巨大的方面/ JavaScript的。 因此,作者引入了新的聲明符, letconst ,其目標是塊作用域和可預測的,更像您在其他語言中看到的其他聲明符。 因此,只要在同一范圍內有另一個聲明, letconst聲明就會拋出錯誤。 這與window無關,僅僅是因為兼容性和歷史問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM