1. 程式人生 > >JavaScript的作用域

JavaScript的作用域

一般談到js中的作用域,則跨不過function這個物件,js的函式都表示為一個物件,具體說就是Function的一個例項。它與其他物件一樣,可以進行屬性的增加刪減等

var f = function(){};
f.a = 1;

這裡的a就是可以被直接訪問的屬性,當然f有一些不能被外部僅供js引擎存取的內部屬性,其中一個內部屬性為[[Scope]],這個內部屬性包含了一個函式被建立的作用域中物件的集合。這個集合被稱為函式的作用域鏈,它決定了哪些資料可以被函式訪問。當一個函式建立後,它的作用域鏈會被建立此函式的作用域中可訪問的資料物件所填充。

function a(num1,num2){
      var sum = num1  + num2;
      return sum;
}

此函式在全域性的環境中建立,則在建立的時候其的作用域鏈就已經被入棧了一個物件,該物件指向的便是所有的在全域性中定義的變數。

在這裡插入圖片描述

在函式a執行的時候會建立一個被稱為執行環境的內部物件,一個執行環境定義了一個函式執行的時候的環境。每次執行函式都會產生一個對應的執行環境,每次函式執行完畢其執行環境便會被銷燬。 當執行環境被建立的時候,其作用域鏈初始化為當前執行函式的[[Scope]]屬性中的物件。在函式內部出現的值按照它們出現在函式中的順序被複制到執行環境中的作用域鏈中,一旦此過程被完成,則一個稱謂活動物件的新物件就被建立好了,此物件包含了所有區域性變數,命名引數,引數集合以及this,然後該活動物件被插入了作用域鏈的最前端,當執行環境消失的時候,該活動物件也隨之消失。 在這裡插入圖片描述

在執行的時候,引數尋找便按照執行環境的作用域鏈進行尋找,而this只會尋找到其活動物件結束為止。 關於閉包: 在這裡插入圖片描述 上圖中Closure是assignEvents的一個閉包,當assignEvents執行的時候,其執行環境如其指標所示,其棧頂端是活動物件,然後是其[[Scope]]物件的複製。 而閉包Closure在被建立的時候,其環境便是assignEvents的執行環境,因此它的作用域中便會將assignEvents執行時候所有的物件儲存下來。 當其自己執行的時候,執行環境被建立,則它的頂端是其自有的活動物件,然後便是其複製OK的作用域(包含了assignEvents的活動物件)。 因此這便是閉關能夠訪問其父方法內部物件的原理。 閉包的[[Scope]]中會有assignEvents活動物件的引用,因此原本應該被銷燬的assignEvents的活動物件便無法被銷燬,由此閉包需要更大的記憶體開銷([[Scope]]的增大以及執行環境被建立時候記憶體開銷的增大),會導致記憶體洩漏。