2012-06-21 62 views
5

我想了解JavaScript作用域規則。我在教科書和文檔中讀到的內容令人困惑。JavaScript範圍和執行上下文

在我看來,JavaScript是一種靜態(或詞法)範圍的語言 - 當試圖將變量名綁定到變量(定義)時,將使用代碼的詞法結構。

執行上下文似乎與調用堆棧上的堆棧幀相似。每個執行上下文都有一個變量對象,其上定義了所有局部變量(關聯函數的)。這些變量對象被鏈接在一起,從堆棧頂部的變量對象到堆棧底部的變量對象(窗口對象)提供一個'範圍鏈'。通過將變量名稱綁定到變量,從上到下搜索此作用域鏈。這與靜態範圍的語言(如C/C++/Java)非常相似。

C/C++/Java似乎有一個重要區別 - 可以訪問一個函數中定義的變量,該變量的棧幀不再位於調用棧中,如下例所示:

var color = "red"; 
var printColor; 

function changeColor() { 
    var color = "green"; 

    printColor = function(msg) { 
     alert(msg + color); 
    } 
    printColor("in changeColor context, color = "); // "green" 
} 

changeColor(); 

// stack frame for "changeColor" no longer on stack 
// but we can access the value of the variable color defined in that function 

printColor("in global context, color = "); // "green" 

我有這個權利嗎?我應該注意到其他問題嗎?

預先感謝

+4

非常透徹後命中HN今天倒是這樣:[什麼是執行上下文和堆棧在JavaScript?](http://davidshariff.com/blog/what-is-the-execution-context-in- javascript /) –

+2

這被稱爲*閉包*。您分配給'printColor'的函數即使在函數終止後也可以訪問'changeColor'中定義的所有變量。我不知道這是怎麼在C –

+0

幾乎@FelixKling。但changeColor也是在全局範圍上定義的,因此它的範圍將永遠不會被垃圾收集。 – webduvet

回答

2

這確實是C/C++和JavaScript之間的主要區別是:JavaScript是 引用計數,垃圾回收的語言,這意味着對象可以 由發動機被回收時,他們不再有任何對它們的引用。 您分配給printColor的功能本身不在堆棧中,因爲它的 將使用C或C++;它會動態分配,然後分配給 一個您當前範圍之外的變量。所以,當從 changeColor控制流返回,匿名功能仍具有由於外printColor的 引用計數是指它,因此它是從外 範圍可用。

所以,你的例子與其說是一個範圍問題 - 很明顯,你聲明 printColorchangeColor功能範圍。當你定義 changeColor時,它將 closes的值提升 printColor進入新的函數範圍,使其可訪問。像 戰鬥說,如果你添加一個var到第二,內部定義的 printColor,它會 shadow第一 printColor你宣告,它不會是功能 塊外訪問。

至於其他問題要注意,是的,有不少,但看到我的 評論您的原始帖子一個良好的開端。

+0

唉,我可能已經誤解了問題(w.r.t.了'color'變量),但我覺得我寫的還是站得住腳。 –

+0

當你說printColor不是在棧上,我相信你的意思是代表printColor的對象。當printColor被調用時,它的執行上下文/棧幀被壓入堆棧。或者我錯了嗎? – asterix

0

它總是歸結爲詞法範圍界定,它是在定義範圍鏈時執行的,而不是在調用範圍鏈時執行。

匿名函數在本地函數changeColor範圍內定義,而不是全局範圍。因此,當它再次執行時,它會打印出在本地範圍的changeColor中列出的綠色。