摘要:因此我們可以說變量對象包含了活動對象,活動對象就是作用域鏈上正在被執行和引用的變量對象。
看一下是知乎大神對于 js 執行環境 活動對象 變量對象 作用域鏈的解釋
假設在全局環境下定義了函數pub()和變量pubvar:
var pubvar = 1; function pub () { var pravar = 2; return pubvar + pravar; } alert(pub(2)); //調用pub()函數
當代碼在一個環境中執行時,會創建變量對象的一個作用域鏈(scope chain),這個作用域鏈包含了全局環境的變量對象(執行環境中定義的所有變量和函數都保存在這個對象中)并被保存在pub()函數內部的scope屬性中。但是,當我們打開瀏覽器的時候已經存在了一個全局的執行環境,這個全局的執行環境屬于瀏覽器,JS里瀏覽器被稱為window對象,我們把這個環境叫做A環境,只要沒有關閉瀏覽器,A環境會一直存在下面會提到執行環境什么時候會被創建。我們用色塊表示執行環境,鏈條表示作用域鏈,作用域鏈上半部分是活動對象區域,下半部分是變量對象區域,如下圖:
當我們調用pub()函數的時候,會在全局執行環境A中創建一個執行環境B,沒錯,執行環境如其名是在運行和執行代碼的時候才存在的,所以我們運行瀏覽器的時候會創建全局的執行環境。這個時候根據pub()函數scope屬性中的作用域鏈把pub()函數內的變量對象放入新的B環境中,作用域鏈也得到更新,如下圖:
上圖的虛線表示正在執行,全局變量對象此時處于作用域鏈的第二位所以標號變成了1。你可能也注意到那個arguments對象,它是在函數被創建的時候就一直存在的,無需用戶創建。arguments對象保存的是函數圓括號內定義的參數,準確來說保存的是參數的值,因這里我們沒有設置參數,所以顯示未定義。此時我們把屬于B環境的變量對象(也就是pub()函數中的所有函數和變量)叫做活動對象。因此我們可以說變量對象包含了活動對象,活動對象就是作用域鏈上正在被執行和引用的變量對象。我們從活動對象的名稱中也能看出 “執行、運行、激活” 等意味。你可以這樣理解,整個代碼的運行總有一個起始的對象吧,不管這個起始是變量還是函數,總要有一個稱呼,雖然我們把執行環境中的變量和函數的總稱叫做變量對象,但這不能反映代碼的動態性,為了區別于普通的變量對象,我們創造了活動對象的概念。
我們把上面的代碼變成如下:
var pubvar = 1; function pub () { var pravar = 2; return pubvar + pravar; } var pubvar2 = 3; function pub2 () { var pravar = 2; return pubvar2 + pravar; } alert(pub(2)); //調用pub()函數
這個時候全局的作用于鏈和執行環境如下
接著我們調用pub()函數,執行環境和作用域鏈如下:
你看沒有被調用的pub2()函數仍然只是閑著,甚至沒有被pub()函數在內部引用。由于pub2()沒有參與整個pub()函數的調用過程,所以pub2()中不存在活動對象,只有“處于靜止狀態”的變量對象,當然也沒有創建執行環境(因為它根本沒執行嘛)。
到這里就完了?也沒有,我們剛才也只是討論了兩個平行且毫不關聯的函數其中一個被調用的狀況,言下之意就是也存在函數相互影響的例子,最典型的就是閉包,閉包是一種函數嵌套的情況。定義如下代碼:
function returnfunc (propertyName) { return function (obj) { //-----這行定義并返回了一個閉包,也被稱之為一個匿名函數 return obj[propertyName]; //這里用方括號法訪問屬性,因為屬性是變量(returnfunc()函數的參數) }; } var savefunc = returnfunc("name"); //調用returnfunc() var result = savefunc({name:"Picasso"});//調用savefunc() alert(result); //返回字符串“Picasso”
最開始的執行環境和作用域鏈
我們先開始調用returnfunc()函數,馬上會創建一個包含returnfunc()變量對象的行環境,作用域鏈開始變化,如下圖:
圖的白色虛線表示執行程序產生的效果,它可能表示的是返回一個結果、復制某種值、產生一個新物體、建立某種聯系等。
題外話:你會發現上圖的arguments參數的值和propertyName的值是一樣的,這是因為arguments保存的就是參數,采用實時映射的方式與參數建立聯系,如果你在returnfunc()函數內再加一個值為{name:"picasso"},名為obj的參數,那么arguments的值變成[{name:"nicholas"},{name:picasso}],是的,你沒看錯,arguments是一個數組!!!
隨后returnfunc()函數會返回它內部的匿名函數,當匿名函數被返回后,整個作用域鏈和執行環境又發生了變化:
我們看到匿名函數(閉包)被添加到了最作用域鏈的最前端,returnfunc()的執行環境被銷毀,但我們注意到returnfunc()函數的活動對象仍然在被引用(匿名函數仍在訪問propertyName參數),因此returnfunc()函數的變量對象仍然在內存中,成為活動對象。這就是為什么匿名函數就能訪問returnfunc()函數定義的所有變量和全局環境定義的變量,畢竟returnfunc()的活動對象仍然保持“激活”狀態。
根據上面所述,隨著代碼一行一行的被執行、執行環境不斷被創建和銷毀、變量對象間的各種關系被建立,這些背后的邏輯導致活動對象也在不斷變化,這足以證明活動對象只是正在被執行和引用的變量對象。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/92808.html
摘要:至此作用域鏈創建完畢。好了,通過深入理解作用域鏈,我們能跟好的理解的運行機制和閉包的原理。 前言 理解javascript中的作用域和作用域鏈對我們理解js這們語言。這次想深入的聊下關于js執行的內部機制,主要討論下,作用域,作用域鏈,閉包的概念。為了更好的理解這些東西,我模擬了當一個函數執行時,js引擎做了哪些事情--那些我們看不見的動作。 關鍵詞: 執行環境 作用域 作用域鏈 變...
摘要:全局執行環境的變量對象始終是作用域鏈中的最后一個變量對象。綜上,每個函數對應一個執行環境,每個執行環境對應一個變量對象,而多個變量對象構成了作用域鏈,如果當前執行環境是函數,那么其活動對象在作用域鏈的前端。 1.幾個概念 先說幾個概念:函數、執行環境、變量對象、作用域鏈、活動對象。這幾個東東之間有什么關系呢,往下看~ 函數 函數大家都知道,我想說的是,js中,在函數內部有兩個特殊...
摘要:下面我們就羅列閉包的幾個常見問題,從回答問題的角度來理解和定義你們心中的閉包。函數可以通過作用域鏈相互關聯起來,函數內部的變量可以保存在其他函數作用域內,這種特性在計算機科學文獻中稱為閉包。 寫這篇文章之前,我對閉包的概念及原理模糊不清,一直以來都是以通俗的外層函數包裹內層....來欺騙自己。并沒有說這種說法的對與錯,我只是不想擁有從眾心理或者也可以說如果我們說出更好更低層的東西,逼格...
摘要:所以,全局執行環境的變量對象始終都是作用域鏈中的最后一個對象。講到這里,可能你已經對執行環境執行環境對象變量對象作用域作用域鏈的理解已經他們之間的關系有了一個較清晰的認識。 JavaScript中的執行環境、作用域、作用域鏈、閉包一直是一個非常有意思的話題,很多博主和大神都分享過相關的文章。這些知識點不僅比較抽象,不易理解,更重要的是與這些知識點相關的問題在面試中高頻出現。之前我也看過...
閱讀 1054·2021-11-15 18:11
閱讀 3177·2021-09-22 15:33
閱讀 3471·2021-09-01 11:42
閱讀 2666·2021-08-24 10:03
閱讀 3631·2021-07-29 13:50
閱讀 2934·2019-08-30 14:08
閱讀 1284·2019-08-28 17:56
閱讀 2267·2019-08-26 13:57