掌握函式執行過程,作用域鏈

2022-10-10 22:33:24 字數 3309 閱讀 4475

我們在了解了全域性**的執行和作用域的提公升後,我們接下來理解比較特殊的函式執行作用域鏈

**被解析,開闢函式記憶體空間,go中引用函式位址。

通過全域性**的變數提公升我們知道,在**解析過程中,會生成全域性物件global object (go),並在其中對全域性的變數進行定義,函式在這個期間也會被定義,並生成一塊該函式專屬的記憶體空間,通過引用的形式訪問。

var name = 'mjy'

foo(123)

function foo(num)

// **被解析,瀏覽器引擎內部會幫助我們建立乙個go物件

var globalobject =

在函式開闢的空間中:存放函式的作用域 scope和函式執行體(**塊),作用域為當前函式的父級作用域,也就是說:函式的作用域在函式還沒執行前就在記憶體中定義好了。這個點很重要

圖示:函式執行前,產生fec,ao物件,fec入棧

在函式**執行時,js會建立乙個函式執行上下文fec(functional execution context), 並將函式執行上下文fec,加入到執行上下文棧ecstack(execution context stack)中。

在fec函式的執行上下文棧中,和全域性執行上下文gec一樣,同樣有著vo物件,此時的vo物件指像的是函式建立的ao(activation object)物件。和全域性執行上下文不同的是,函式的fec函式的執行上下文棧中還有著作用域鏈,其值為當前的作用域ao + go

function foo(num) 

// foo函式的啟用物件ao

activationobject =

foo(123)

// 當函式執行時,依次為ao物件中的變數賦值

activationobject =

函式呼叫函式的執行過程

當函式**現了巢狀函式時,在外層函式的ao中,也是通過存放位址的引用形式來引用函式的 。函式在記憶體堆中的示意圖是這樣的

函式中變數的查詢過程

當我們在函式中查詢乙個變數時, 查詢的路徑是在自身的fec中沿著作用域鏈 scope chain 來查詢的,

作用域鏈的值為scopechain:自身作用域ao + 父級作用域paraentscope

例如下面這段**

var message = "hello global"

function foo()

function bar()

bar() // 輸出的是:hello global

foo函式的ao物件中並沒有message變數,此時它就會沿著作用域鏈scopechain去父級作用域中查詢,而foo函式的父級作用域在foo函式開闢記憶體空間時,就已經是定義好的了,其值就是全域性作用域go。從而就找到了go中的message。

由此得出:函式作用域跟定義位置有關係,跟呼叫的位置沒有關係

圖示:總結:**解析時:**中定義了函式,為其開闢自己的函式空間,函式空間中存放著父級作用域和函式體。

函式執行前(函式只有將要被執行才會有這一步):建立函式執行上下文fec,ao函式活躍物件,ao物件中存放著函式中定義的變數。fec中存放著vo物件指向ao,和函式的作用域鏈條scopechain,作用域鏈值為ao+函式記憶體中定義的父級作用域。

函式執行時:函式執行上下文fec入棧ecs。**依次執行,為ao物件中定義的變數賦值。

函式執行後:開闢的函式記憶體空間銷毀,釋放記憶體。函式的ao物件與記憶體空間不復存在。

若函式中巢狀了函式,在父級函式執行前,就說父級函式ao建立時會被讀取到,在堆中開闢出新的函式記憶體空間,通過址引用的方法關聯。當巢狀函式執行時,執行上面的4步驟。

當我們在函式中查詢變數時:會根據函式的作用域鏈來查詢,先查詢自身ao物件,再去作用域中查詢。函式的作用域跟定義位置有關係,跟呼叫的位置沒有關係(函式的作用域在函式還沒執行前就在記憶體中定義好了)。

面試題:

1.函式的作用域

var n = 100

function foo()

foo()

console.log(n)

2.函式的執行過程

function foo() 

var n = 100

foo()

3.函式的作用域鏈

var n = 100

function foo1()

function foo2()

foo2()

console.log(n)

4.函式的返回值

var a = 100

function foo()

foo()

5.函式的作用域與作用域鏈與全域性變數

function foo() 

foo()

console.log(a)

console.log(b)

題解:

1.沿著作用域鏈scopechain查詢到go中的變數n,並且為其賦值為200

2.**還沒執行,ao物件中變數n的值為初值undefined,當執行到了賦值語句,n的值才會改變。

undefined

200

3.foo1的ao物件中並沒有變數n,去作用域鏈中的父級作用域go中查詢。

foo2中ao物件中有變數n,且輸出語句前已經賦值。

200

100100

4.函式的返回值在ao中也是有定義的

5.全域性物件go中並沒有定義變數a,所以輸出a報錯。

在函式中沒有定義的 b 賦值為100, b = 100,嚴格來說這是乙個錯誤的語法,但js允許這麼寫,它會沿著作用域去查詢,最終到go中定義乙個變數b,並將其賦值。

報錯:a is not defined

js 作用域,作用域鏈,立即執行函式,閉包

作用域 1全域性作用域 全域性作用域就是最外層函式定義的變數,對任何內部函式來說,都是可以訪問的。2.區域性作用域 區域性作用域就是只在固定 片段內可以訪問到,在函式外部是無法訪問的。函式外是不可以訪問到函式內的,所以報錯。作用域鏈 scope 中所儲存的執行期上下文物件的集合,這個集合成鏈式鏈結,...

執行環境,作用域,作用域鏈詳解

宣告 該文章有些概念摘自 j ascript高階程式設計 1 執行環境 也稱 環境 執行環境定義了變數或函式有權訪問的其他資料,決定了他們各自的行為。全域性定義的變數,函式裡面可以訪問。一般情況下,函式裡面定義的變數,全域性無法訪問 2 全域性執行環境 全域性執行環境是最外圍的一直執行環境,在web...

函式作用域和作用域鏈

所謂作用域就是 變數在宣告它們的函式體以及這個函式體巢狀的任意函式體內都是有定義的。function scope while 1 function console.log foo,global a,i m if b,i m while c c is not defined scope 但是,在js中...