javascript作用域及作用域鏈

從事web開發工作,尤其主要是做服務器端開發的,難免會對客戶端語言JavaScript一些概念有些似懂非懂的,甚至僅停留在實現功能的層面上,接下來的文章,是記錄我對JavaScript的一些概念的理解。歡迎大牛拍磚吐糟。

1.變量作用域

在JavaScript中全局變量的作用域比較簡單,它的作用域是全局的,在代碼的任何地方都是有定義的。然而函數的參數和局部變量只在函數體內有定義。另外局部變量的優先級要高於同名的全局變量,也就是說當局部變量與全局變量重名時,局部變量會覆蓋全局變量(如下面例子)。

複製代碼
var num = 1;            //聲明一個全局變量
   function func() {
      var num = 2;        //聲明一個局部變量
       return num;
   }
   console.log(func());    //輸出:2

 注:聲明局部變量時一定要使用var,否則,解釋器會將該變量當做全局對象window的屬性。

2.函數作用域

在JavaScript中變量的作用域,並非和C、Java等編程語言似得,在變量聲明的代碼段之外是不可見的,我們通常稱爲塊級作用域,然而在JavaScript中使用的是函數作用域(變量在聲明它們的函數體以及這個函數體嵌套的任意函數體都是有定義的)。(如下面的例子)

複製代碼
        function func() {
            console.log(num);           //輸出:undefined,而非報錯,因爲變量num在整個函數體內都是有定義的
            var num = 1;                //聲明num 在整個函數體func內都有定義
            console.log(num);           //輸出:1
        }
        func();

注:JavaScript的函數作用域是指在在函數內聲明的所有變量在函數體內始終是可見的,也就是說在函數體內變量聲明之前就已經可用了。

作爲屬性的變量

當聲明一個全局變量的時候,實際上是定義了全局對象window的一個屬性。

        var num = 1;            //聲明全變量num
        alert(window.num)       //輸出:1 聲明的全局變量實際上就是聲明瞭一個window對象的屬性

 

3.作用域鏈

在JavaScript中,函數也是對象,實際上,JavaScript裏一切都是對象。函數對象和其它對象一樣,擁有可以通過代碼訪問的屬性和一系列僅供JavaScript引擎訪問的內部屬性。其中一個內部屬性是[[Scope]],該內部屬性包含了函數被創建的作用域中對象的集合,這個集合被稱爲函數的作用域鏈,它決定了哪些數據能被函數訪問。

當一個函數創建後,它實際上保存一個作用域鏈,並且作用域鏈會被創建此函數的作用域中可訪問的數據對象填充。例如定義下面這樣一個函數:

        function func() {
            var num = 1;
            alert(num);
        }
        func();

在函數func創建時,它的作用域鏈中會填入一個全局對象,該全局對象包含了所有全局變量,如下圖所示(注意:圖片只例舉了全部變量中的一部分):

 函數add的作用域將會在執行時用到。例如執行如下代碼:

執行此函數時會創建一個稱爲“運行期上下文(execution context)”(有人稱爲運行環境)的內部對象,運行期上下文定義了函數執行時的環境。每個運行期上下文都有自己的作用域鏈,用於標識符解析,當運行期上下文被創建時,而它的作用域鏈初始化爲當前運行函數的[[Scope]]所包含的對象。

  這些值按照它們出現在函數中的順序被複制到運行期上下文的作用域鏈中。它們共同組成了一個新的對象,叫“活動對象(activation object)”,該對象包含了函數的所有局部變量、命名參數、參數集合以及this,然後此對象會被推入作用域鏈的前端,當運行期上下文被銷燬,活動對象也隨之銷燬。新的作用域鏈如下圖所示:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章