2014-04-04 32 views
3

編輯:謝謝你的答案,我想我現在得到它。它需要了解範圍和提升。下面是一個新實例,我認爲示出兩個孔:如果函數的詞法環境是在函數被定義時創建的,那麼爲什麼可以在函數之後聲明一個自由變量?

var a = function(){ 
    alert(x); 
} 
var x = 1; 

(function(){ 
    var x = 2; 
    a(); 
})(); 

上述警告1.詞彙範圍由以下事實:這個警報1和不是2,並且曳引由以下事實說明示出的是「無功x = 1「行用」alert(x)「聲明匿名函數並定義。據稱,起重裝置,上述等效於以下(來源:http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html):

var x; 
var a = function(){ 
    alert(x); 
} 
x = 1; 

(function(){ 
    var x = 2; 
    a(); 
})(); 

所以由於x被有效地初始化函數定義之前,在X「警報(X)」是相同X,其隨後被設置爲1。

由於JS使用詞法作用域,行「VAR X = 2」不覆蓋與一個相關聯的X

這是對的嗎?

---原題---

我花了幾乎一整天試圖弄清楚這一點。我已經閱讀了一些關於範圍和關閉Javascript的文章,但這仍然沒有我。

我被告知,函數的詞法環境是在定義函數時創建的,而不是在執行時創建的。

所以,如果沒有名爲X在我的程序的任何地方聲明的變量,那麼什麼是匿名函數封閉環境當我做到這一點?:

var a = func(){ 
    var y = 7; //just for illustrative purposes 
    alert(x); 
}); 

點我理解是環境是變量名稱到值的映射......所以它將是

y: 7 
x: ? 

這是正確的嗎?下面的代碼警報「10」:

(function(){ 
    var a = function(){ 
     alert(x); 
    }; 
    var x = 10; 
    a(); 
})(); 

我的猜測是,當一個被調用時,JS檢查封閉環境爲X的映射,仍然沒有找到,接着檢查當地環境並通過「var x = 10」將x設置爲10。是對的嗎?

如果是這樣的話,那麼我希望下面還要工作的,但它並不:

var a = function(){ 
    alert(x); 
}; 

(function(){ 
    var x = 10; 
    a(); 
})(); 

我會希望出現的情況是,當執行一個和「警報(X);」運行時,它會檢查關閉環境x,找不到,然後檢查「var x = 10」所在的外部環境,並找到x。但相反,我得到一個錯誤,沒有定義x

如果我能夠知道當設置的最初定義的匿名函數是最初定義的時候解釋器做了什麼「準備工作」,也就是說,當口譯人員在「alert(x)」中遇到x時。

感謝

+0

好問題。答案是詞法和動態範圍的區別。 Javascript並沒有真正的後者,除了全局變量 –

+0

IIFE創建了一個局部範圍,這就是爲什麼最後一個不起作用,IIFE的工作方式稍有不同,更像變量。 – adeneo

+0

@NiklasB。那麼一個函數的詞法範圍就包含了它的定義之後發生了什麼,也就是說,當「var x = 10」發生在函數的定義之後,但是在相同的「深度」時,它實際上是在修改函數的詞法範圍? – user3391564

回答

1

將封閉視爲堆棧。每個函數在該堆棧中都有一個map/hash。下面是一個例子,其中每個級別都有一個被子閉包覆蓋的x值。

function a(){ 
    var x = 2; 
    function b(){ 
    var x = 3; 
    function c(){ 
     var x = 4; 
    } 
    } 
} 

當引用x的值時,js處理器在當前閉包中查找。發現未定義,它向上走向閉包堆棧,試圖找到一個值。只有達到頂級或「全球」範圍時,才放棄並賦予「未定義」的價值。

你舉的例子在這裏:

var a = function(){ 
    alert(x); //no value of x in this closure 
}; 

//no value of x in this closure either 

(function(){ 
    var x = 10; //this is a completely separate stack 
    a(); //no value of 'a' in this closure, but there is one in global scope  
})(); 

我可以看到在匿名函數不知道有關的「X」的「a」功能的混亂。封閉範圍被定義爲「書面」而不是「被稱爲」。您不能從封閉範圍外注入或混淆函數閉包中的變量。這是關於js的事情之一,這讓我瘋狂,我希望是不同的。我很想擁有一組關鍵字來處理封閉範圍...

+0

我想我明白了。所以當_a_被調用時,不管它在哪裏,它首先在原始作用域(在_a_分配的原始匿名函數內部)尋找,然後從那裏去?換句話說,它首先查找_x_在哪裏寫了「在這個閉包中沒有x的值」,然後看看你寫了「在這個閉包中沒有x的值」,但從來不會在函數內部調用它? – user3391564

2

的JS檢查對於x的映射封閉環境中,仍然沒有找到

事實上,它確實找到一個。 var聲明的位置並不重要,名稱x仍然是綁定到外層函數的關閉。您可以考慮在解析步驟中收集的聲明並將其移至前面(此過程稱爲提升)。

將源代碼中圍繞表達式的示波器向上移動的過程稱爲詞法綁定。

對於你的第二個工作例子,你需要動態綁定,JS不支持(globals除外)。

相關問題