執行環境 作用域鏈及閉包

2022-03-28 18:37:29 字數 1805 閱讀 3546

執行環境(execution context)定義了變數或函式有權訪問的其他資料,決定了他們各自的行為。每個執行環境都有乙個與之關聯的變數物件(variable object),環境中定義的所有變數、形參和函式宣告都儲存在這個物件中。編碼時無法訪問這個變數物件,解析器在處理資料時會在後台使用。

在web瀏覽器中,全域性執行環境被認為是window物件(全域性執行環境所關聯的物件就是window物件),因此所有的全域性變數和函式都是作為window物件的屬性和方法來建立的。某執行環境中的所有**執行完畢後,該環境被銷毀,儲存在其中的所有變數和函式也隨之銷毀(全域性執行環境直到應用程式退出時才會被銷毀)。

每個函式都有自己的執行環境。當執行流進入乙個函式時,函式的執行環境就會被推入乙個環境棧中。而在函式執行完畢後,棧將其環境彈出,把控制權返回給之前的執行環境(後進先出)。ecmascript程式中的執行流正是由這個方便的機制控制著。

當**在乙個執行環境中執行時,會建立變數物件的乙個作用域鏈(scope chain)。作用域鏈的用途,是保證對執行環境有權訪問的所有變數和函式的有序訪問。作用域鏈的前端,始終都是當前執行的**所在環境的變數物件。如果這個環境是函式,則將其活動物件(activation object:函式呼叫中的變數物件)作為變數物件。活動物件最開始時只包含乙個變數,即arguments物件。作用域鏈中的下乙個變數物件來自包含(外部)環境,而再下乙個變數物件則來自下乙個包含環境。這樣,一直延續到全域性執行環境:全域性執行環境的變數物件始終都是作用域鏈中的最後乙個物件。

當某個函式被呼叫時,會建立乙個執行環境(execution context)及相應的作用域鏈。然後,使用 arguments 和其他命名引數的值來初始化函式的活動物件(activation object)。但在作用域鏈中,外部函式的活動物件始終處於第二位,外部函式的外部函式的活動物件處於第三位,……直至作為作用域鏈終點的全域性執行環境。

在定義函式時,會建立乙個從包含函式的活動變數物件到全域性變數物件的作用域鏈,這個作用域鏈被儲存在內部的 [[scope]] 屬性中,該屬性不能被開發者訪問。即js函式的作用域鏈是在函式定義時就被確定好,而不是執行時才確定的。當呼叫函式時,會為函式建立乙個執行環境,然後通過複製函式的 [[scope]] 屬性中的物件構建起執行環境的作用域鏈。最後,會有乙個當前函式的活動物件(在此作為變數物件使用)被建立並被推入執行環境作用域鏈的最前端。作用域鏈本質上是乙個指向變數物件的指標列表,它只引用但不實際包含變數物件。

每個函式在定義時就有內部屬性[[scope]],儲存了從包含環境的變數物件,一層一層往外擴,直到全域性環境的變數物件的作用域鏈。

每個函式執行時,引擎都會建立與之對應的執行環境壓入ec棧中。同時執行環境通過複製[[scope]]中的變數物件構建作用域鏈,初始化活動物件ao(包括arguments和其他命名的變數)並壓入作用域鏈的最前端,指定this的值。

在另乙個函式內部定義的函式會將包含函式(即外部函式)的活動物件新增到它的作用域鏈中。如果內部函式被返回出外部函式而繼續存在,則當外部函式被銷毀時,其活動物件因為仍然被內部函式的內部屬性[[scope]]作用域鏈所引用而繼續留在記憶體中。

function

outer()

}

如果outer不呼叫,內部的匿名函式不算被定義,對應的[[scope]]屬性也不存在。如果outer被呼叫,但不返回匿名函式,[[scope]]會出現,但隨著匿名函式被**也被銷毀。只有匿名函式被返回後,[[scope]]才會一直存在,對應的outer的活動變數也會因為被匿名函式的作用域鏈引用而一直存在。

作用域,閉包,作用域鏈

一,作用域 變數在宣告它的函式及該函式所巢狀的任意函式是有定義的 例var num 2 function fun fun 二,作用域鏈 多個函式巢狀在一起,多個作用域相互巢狀,這是作用域鏈 var num 1 function fun function fun2 fun1 fun2 fun 訪問原則...

作用域 作用域鏈 閉包

閉包概念中的一些專業名詞概念不清晰 作用域鏈 本質是乙個指向變數物件的指標列表。函式的作用域鏈在函式呼叫完成後即被銷毀。變數物件 全域性變數物件 js執行時一直存在 活動變數物件 區域性變數物件,函式執行完畢後銷毀 函式在呼叫時建立本地的活動物件加上函式定義時預建立的作用域鏈,形成乙個新的用於執行函...

作用域 執行環境 閉包(四)

上一期我們已經介紹了閉包,由於閉包可以延長函式內部的變數的生存週期,因此我們可以將不需要暴露在全域性的變數封裝成函式的內部變數,從而避免 汙染。譬如要實現乙個簡單的累加器,為了儲存每次累加的結果,因此宣告了乙個全域性變數total,如下 var total 0 function add t tota...