環(huán)境模型這詞來自于《SICP》這本書。
> The environment is crucial to the evaluation process, because it determines the context in which an
expression should be evaluated.
Indeed, one could say that expressions in a programming language do not,in themselves, have any meaning. Rather, an expression acquires a meaning only with respect to some environment in which it is evaluated. Even the interpretation of an expression as straightforward as (+ 1 1) depends on an understanding that one is operating in a context in which + is the symbol for addition.
> 環(huán)境對于求值過程是至關重要的,因為它確定了表達式求值的上下文。
實際上,我們可以認為表達式本身在一個程序語言里沒有任何意義。一個表達式的意義取決于他求值時所在的環(huán)境。甚至像(+ 1 1)這樣一個極其簡單的表達式的解釋過程,都需要在一個符號+表示加法的上下文里執(zhí)行。
ES的環(huán)境,可以看作是變量約束存在的上下文,變量的值取決于他所在的環(huán)境。
# 環(huán)境的訪問
* 使用**var**關鍵字就能將變量約束加入當前環(huán)境。
* 使用一個變量時,如果當前環(huán)境不存在他的約束,會嘗試從外層的環(huán)境中訪問。
~~~
var x = 2017;
var foo = function () {
x = x + 1;
}
foo();
console.dir(x);//2018
~~~
以上代碼執(zhí)行時存在兩個環(huán)境。
環(huán)境一是定義foo函數(shù)時所在的環(huán)境,該環(huán)境存在兩個變量約束,變量x,變量foo。
環(huán)境二是執(zhí)行foo函數(shù)時產(chǎn)生的環(huán)境,不存在變量約束。
因此,在環(huán)境二中訪問變量x時,環(huán)境二不存在變量x的約束。接著,變量x就會引用外層環(huán)境中的約束(x,2017),在函數(shù)中進行x=x+1修改x的值。最后,在環(huán)境一中,用console.dir(x)打印x的值2018。
# 環(huán)境的生成
環(huán)境是由函數(shù)生成的。
* 一個函數(shù)在定義時,會保存所在環(huán)境的引用。
* 一個函數(shù)在執(zhí)行時,會產(chǎn)生一個新的環(huán)境。該環(huán)境除了包含變量的約束外,還存在一個指向函數(shù)定義時所在環(huán)境的引用。
舉個例子:
~~~
var generator = function () {
var n = 0;
return function () {
var result = n;
n = n + 1;
return result;
};
};
var counter = generator();
console.dir(counter());//0
console.dir(counter());//1
console.dir(counter());//2
~~~
generator函數(shù)在執(zhí)行時,產(chǎn)生了一個新環(huán)境G。環(huán)境G存在變量n的約束,并且定義和返回了一個函數(shù),該函數(shù)保存了環(huán)境G的引用。
counter變量得到generator返回的函數(shù)對象,我們可以將counter視為一個函數(shù)。
每次執(zhí)行counter函數(shù),都產(chǎn)生一個新環(huán)境Cx,環(huán)境Cx存在一個指向環(huán)境G的引用。在環(huán)境Cx使用變量n時,由于環(huán)境Cx不存在變量n的約束,程序就會嘗試從環(huán)境Cx引用的環(huán)境G中尋找。
因此,每次執(zhí)行counter函數(shù)都使得環(huán)境G的n+1,得到上面的結果。

這也是所謂的閉包。(閉包指的是他實現(xiàn)用的技術,而不是他的行為。)
> 一個操作組合而來的結果能通過同樣的操作進行組合,就是說明該操作滿足閉包性質。
# 環(huán)境的回收
環(huán)境里包含著變量的約束,變量的約束是會占據(jù)計算機的資源的,于是就需要回收環(huán)境釋放變量約束占據(jù)的資源。
如果一個環(huán)境,不能再被ES程序訪問,回收他就不會有任何副作用了。
那么如何判斷一個環(huán)境不會再被訪問呢?
其實一旦環(huán)境的引用,也就是直接或間接保存著環(huán)境引用的函數(shù),不再存在于其他仍然能被訪問的環(huán)境中,就可以斷定那個環(huán)境再也不會被訪問。ES程序將會自動對其進行回收。
同理,如果一個對象不存在活躍環(huán)境的約束之中,就會被ES自動回收。
這就是所謂的GC。(garbage collection 垃圾回收)
~~~
var funcA = function () {
var obj = {};
};
funcA();//環(huán)境不存在引用,本次funcA執(zhí)行時產(chǎn)生的環(huán)境將被自動回收。
var funcB = function () {
var obj = {}
return function () { };
};
var foo = funcB();//環(huán)境存在引用,本次funcB執(zhí)行時產(chǎn)生的環(huán)境將被保留。
//...
foo = null;//foo約束的函數(shù)失去引用,該函數(shù)所保留的環(huán)境引用不存在于外部環(huán)境,之前funcB產(chǎn)生的環(huán)境將被自動回收。
~~~
