簡體   English   中英

為什么不能用 let 聲明一個和 function 參數同名的變量,連參數都設置默認值?

[英]Why can't use let to declare a variable using the same name as one function parameter, even the parameter get set default value?

在 es2015 中,當你使用默認參數值時,你創建了一個中間值 scope。所以我假設let x在 function 主體中,在不同的 scope 中創建一個新變量。但為什么我仍然得到錯誤?

使用let ,我得到錯誤: 在此處輸入圖像描述

但是使用 var,我在不同的范圍內得到了兩個不同的變量。 為什么? 在此處輸入圖像描述

如果沒有var聲明,結果會改變。 在此處輸入圖像描述

由於它們不在同一個 scope 中,因此let聲明不應引發錯誤。

參數(函數的參數)的范圍是它所屬的函數。

 function check(param) // it has same scope as the parameters declared inside the curly braces,same like declaring variable inside curly braces { let param=2; // throws error as the param is already been declared in scope (let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used.) var param=2 ; // does'nt throw error console.log(param) } check(2)

這與es2015 默認參數值無關,因為它的用途是為函數參數分配默認值。

函數參數(在您的情況下x )自動充當該特定函數的局部變量。 所以變量x已經在該函數中聲明了。

因此,在像foo(7)這樣的函數調用時,您只是將值 7 分配給變量x (已在函數內部聲明)。

如果你想改變里面x的值,那么你可以像下面這樣使用

function foo(x=2) {
    x=5;
    console.log(x); \\ x will be 5
}

即使您使用var關鍵字重新聲明相同的變量名(此處為x ),它實際上也不會重新聲明(因為它已經聲明了)。

為了更好地理解,請嘗試如下

function foo(x=2) {
    var x;
    console.log(x); \\ you may expect x to be undefined here but x will be 2 if you call like foo() or x will be 5 if you call like foo(5)
}

概括:

即使您嘗試重新聲明與上述相同的變量名, var關鍵字也不會拋出任何錯誤。

但是當您嘗試重新聲明相同的變量以避免您現在面臨的此類混淆時, let關鍵字會拋出錯誤。

希望這個詳細的解釋對你有幫助。

這是一個非常有趣的問題,我會盡力給出真實的答案。

簡短回答:正式聲明和 let、const 聲明放在同一個環境中,var 聲明將導致它的一個子環境並從父環境繼承初始化值。

這些都是為了兼容歷史“trouble var”,不引入新的麻煩,給帶默認值的formal params一個自己的閉包(也就是說formal params必須有一個獨立的環境)。

並重新考慮一下:正式聲明和 let、const 聲明放在同一個環境中 它會工作得很好,因為我們不允許重新聲明 let 和 const。

詳情請參見ECMAScript® 2019 語言規范:sec-functiondeclarationinstantiation

好吧,我的簡短回答僅適用於 strict=true 條件,但我們有一個很好的注意:詞法聲明的名稱不能與函數/生成器聲明、形式參數或 var name 相同

反正都是為了兼容 history麻煩 var ,不引入新的麻煩。

  1. 如果嚴格是假的,那么
    1. 令 lexEnv 為NewDeclarativeEnvironment (varEnv)。
    2. 注意:非嚴格函數對頂級詞法聲明使用單獨的詞法環境記錄,以便直接 eval可以確定 eval 代碼引入的任何 var 范圍聲明是否與預先存在的頂級詞法范圍聲明沖突。 這對於嚴格函數來說不是必需的,因為嚴格的直接 eval總是將所有聲明放入一個新的Environment Record
  2. 否則,令 lexEnv 為 varEnv。
  3. 讓 lexEnvRec 成為 lexEnv 的EnvironmentRecord
  4. 將 calleeContext 的 LexicalEnvironment 設置為 lexEnv。
  5. 讓 lexDeclarations 成為代碼的 LexicallyScopedDeclarations。
  6. 對於 lexDeclarations 中的每個元素 d,執行
    1. 注意:詞法聲明的名稱不能與函數/生成器聲明、形式參數或 var name 相同 詞法聲明的名稱僅在此處實例化而不是初始化。
    2. 對於 d 的 BoundNames 的每個元素 dn,執行
      1. 如果 d 的 IsConstantDeclaration 為真,則
      2. 履行 ! lexEnvRec.CreateImmutableBinding(dn, true)。
      3. 別的,
      4. 履行 ! lexEnvRec.CreateMutableBinding(dn, false)。

我們可以認為 function 中的所有變量都在同一個 scope 中。在您的示例中,它在let的情況下給出錯誤,因為在同一個 scope 中的let/const重新聲明給出錯誤,但在使用var的情況下不會。

我們可能會在mdn中看到這樣的說法:

“即使在嚴格模式下,使用var的重復變量聲明也不會觸發錯誤,除非執行另一次賦值,否則變量不會丟失其值。”

暫無
暫無

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

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