2017-08-02 67 views
1

宣稱「讓」變量考慮一下:的ReferenceError在外部範圍

'use strict'; 
 

 
{ 
 
    let p = 1; 
 
    { 
 
    console.log(p); 
 
    let p = 2; 
 
    } 
 
}

一個直覺告訴我們應該記錄爲「1」(因爲VAR必須保留其舊重新宣佈之前的價值)。但是,實際結果是ReferenceError。這是爲什麼? (基於標準的解釋將被讚賞)。

請注意,我已經在外部範圍聲明瞭p,所以它在內部塊中已知。如果你註釋掉p=2這一行,一切正常。

作爲驗屍筆記,雖然這種行爲似乎被記錄,但它仍然是非常直觀的,參見。這個C代碼:

void main() { 
    int p = 1; 
    { 
    printf("%d\n", p); // prints '1' 
    int p = 2; 
    } 
} 

另一個JS fuckup特點要記的!

+3

_「如果你註釋掉p = 2的行,那麼一切正常。」_當然,它確實......你沒有一個衝突的塊範圍變量。 –

回答

10

根據MDN

在ECMAScript中2015,let綁定不受可變吊裝,這意味着讓聲明不移動到當前執行上下文的頂部。在初始化之前引用塊中的變量會導致ReferenceError(與使用var聲明的變量相反,該變量僅具有未定義的值)。變量處於從塊開始到「初始化」處理的「時間死區」。

問題是你的let p語句創建一個新的變量,其範圍是整個代碼塊。因此,在console.log中的p(p);指的是新創建的變量。

相似於您的情況提供一個例子:

function test(){ 
    var foo = 33; 
    if (true) { 
    let foo = (foo + 55); // ReferenceError 
    } 
} 
test(); 

由於詞法作用域,標識符「foo」的表達內側(FOO + 55)的計算結果爲,如果塊的FOO,而不是覆蓋變量foo,其值爲33. 在該行中,if語句塊的「foo」已經在詞法環境中創建,但尚未達到(並終止)其初始化(這是語句本身的一部分) :它仍然處於暫時的死亡地帶。

+0

沒有什麼可說的:完美的答案;-) – trincot

+0

我編輯了這個問題,使我的觀點清晰。 – georg

+0

這是更完美的MDN文章;) – Stephan