2013-04-15 75 views
4

我一直在尋找通過JS庫的代碼之後定義的變量早日回國看到這個模式:如何推理與

function module() { 
    function func() { 
     //... 
     definedAfter(); 
     //... 
    } 
    return func; 
    var x = "...."; 
    function definedAfter() { 
     //... 
     console.log(x); //outputs undefined 
     //... 
    } 
} 

谷歌的Closure編譯器標誌變量x爲未使用的代碼,這似乎合理,但有趣的部分是變量是宣佈的,但值爲undefined(由於起重)。

這是一個庫中的錯誤?還是有一些在這裏被利用的微妙行爲?也許某種類型的優化?對於這個例子,不同的瀏覽器的行爲是不同的嗎?

編輯:我很好奇原始代碼的意圖(錯誤或其他),因爲它似乎總是undefined

+0

'x'應該是'undefined',不'null' ... –

+0

聲明順序並不影響JavaScript的範圍,但執行順序規則應該仍然佔上風,它不會被設置,我很確定。 –

回答

3

我想你明白衝頂,但這裏是一個什麼樣的功能在技術上看起來像一個解釋:

function module() { 
    function func() { 
     //... 
     definedAfter(); 
     //... 
    } 
    function definedAfter() { 
     //... 
     console.log(x); //outputs undefined 
     //... 
    } 
    var x; 
    return func; 
    x = "...."; 
} 

(我不知道的東西實際最終令進行懸掛,但我不」認爲根本是很重要的)

所以最終的x = "....";線將永遠不會被執行,但x仍然會宣佈(如undefined),並且是由內功能範圍進行訪問。

所以我不得不說,圖書館有一個「錯誤」,在這個意義上說,將x設置爲「....」的行永遠不會到達,並且什麼也不做。

+0

你知道任何瀏覽器(特別是IE6或IE7)在該行爲中的變化嗎? x的值實際上與一些IE6/7特定的東西有關,所以它只是讓我懷疑它是壞的還是IE6/7的工作方式不同。 (我並不特別在意支持IE6/7,只是對意圖好奇) – Andrew

+0

@Andrew我不這麼認爲。當'x'是一個全局變量時,情況就不一樣了。但是在當地申報,這種行爲不應該有任何變化。如果'x'是全局的或類似的東西,請看svidgen的答案以瞭解一些事情 – Ian

1

與鴨舌Flynn的註釋行,解析器預掃描和/或它的實際執行之前編譯代碼。因此,它可以檢測塊中任意行的變量作用域,執行或不執行。在瀏覽器的控制檯

運行以下命令:

var f = function() { 
    // we haven't defined a local x yet, so we're tempted to think 
    // that this line is mucking with window.x 
    x = 1; 
    console.log(x, window.x); 
    return; 

    // and we're tempted to think this line is never seen, because it 
    // occurs after the return. but, it ensures that x is local, not global. 
    var x = 2; 
}; 
f(); 

在控制檯,你會看到這樣的內容:

1 undefined 

而且事後,window.x不存在。由於我們的聲明 - 這個聲明的賦值部分是否必要,我沒有把它提到任何地方,我不確定。它不應該。但是,如果知道某個版本的IE在賦值不存在的情況下忽略該聲明,我也不會感到驚訝。

比較它這樣的:

var f = function() { 
    x = 1; 
    console.log(x, window.x); 
    return; 
    x = 2; // this line truly does nothing. 
}; 
f(); 

我們看到在控制檯:

1 1 

而且事後,windows.x1

這也是值得注意的是,definedAfter()工作正常,因爲它不是寫在變量賦值形式:

// this puts definedAfter in scope, but it's undefined unless this line is 
// actually executed 
var definedAfter = function() { /* whatever */ } 

相反,它寫在「函數聲明」的形式,這並沒有得到「執行。「

function definedAfter() { /* whatever */ } 

相反,編譯器在編譯期間看到它,說:‘哦,這個功能範圍的一部分。’這種差異,給您在變量賦值語法來精確控制,當你的功能的能力可以使用。而在函數聲明的形式,在任何地方定義功能,而不必擔心執行順序。

+2

爲什麼通過拋出全局變量來使事情複雜化?指出在函數結尾處省略了什麼'var'很好,但它與爲什麼'x'不是'undefined'的原因沒有任何關係。這就是所謂的變量提升。 – Ian

+0

@Ian它所謂的有點不相關。該宣言的全部目的是使其脫離全球範圍。因此,談論對全球範圍相關的影響...... – svidgen

+0

雖然你對全球範圍是正確的,但它與我在這裏看到的行爲無關,主要是關於本地'x'的價值部分,爲什麼它會是(假設它永遠是'未定義的) – Andrew

0

沒有的能力,這不是在圖書館中的錯誤。然而,這不是最優雅的代碼。

爲了更好地理解它,你需要知道兩件事

1)提示的含義 2)函數表達式和函數聲明之間的區別很微妙,是的,不同的瀏覽器的行爲是不同的。

(後者見:http://kangax.github.io/nfe

歡呼