js深入(二)函數的執行與上下文

這一篇簡單的說一說js的函數執行和js的執行上下文的概念,之前在我的博客裏邊也提到過
js的堆棧隊列
這一篇打算單獨的拿出來說一說

是什麼是js的執行上下文

一段可以執行的代碼在被執行的時候,會創建一個函數的執行上下文

執行上下文裏邊有三個重要的屬性分別是

  • 變量對象
  • 作用域鏈
  • this指向

執行上下文是跟函數相關的,執行上下文分爲兩個階段

創建階段
執行階段
首先創建階段

掃描變量和函數(確定變量環境)
確定this指向
確定詞法環境
簡單說一下詞法環境和變量環境的區別,我個人理解的就是說詞法環境是包含變量環境的

在js裏邊原型鏈大家都不陌生 ,js在當前的對象裏邊找不到所使用的屬性的話會去他的上一級去找
直到Object,再找不到就會undefined ,這裏邊 當前對象的作用域就是他的變量環境,而詞法環境則是與之關聯的的執行上下文中聲明的變量

在創建階段 函數的聲明會被儲存在當前的變量環境之中,var的變量的話則會被設置成undefined
,所以我們在聲明之前就可以訪問到var聲明的變量 ,but他是一個undfined

然後就是執行階段了

這個時候已經完成了對所有變量的分配,開始執行代碼

變量對象

什麼是變量對象,變量對象就是與執行上下文相關得數據得一個作用域,這裏邊存儲了在這個上下文裏邊定義的而變量和函數聲明

函數聲明的時候會在創建階段的時候聲明一個函數指針

全局上下文和函數上下文

全局上下文

故名思與函數上下文,在函數被執行的時候創建,那麼全局上下文是什麼時候被創建的呢,首先我們要知道一個概念就是,全局對象

  • 在一般的函數裏邊全局對象可以用this引用其屬性,客戶端的話是window對象

    console.log(this);

可以嘗試着去打印一下this,如下圖可以看到,window對象裏邊有很多我們常用或者常見的屬性和方法

當然也有一些其他的情況this並不是指向的window對象,this指向 這個東西,我們會在下邊說

  • 當然js 萬物皆對象不只是說說

用 instanceof 輸出一下this 會發現也是一個object

    console.log(this instanceof Object);

所以說全局對象是一個object的實例化對象

所以說說白了全局上下文就是在一開始就被創建的,全局上下文是由在瀏覽器關閉或者刷新的時候纔會銷燬, 然後這個window對象其實就是全局上下文的變量對象

函數上下文

函數上下文和上邊所說的意思差不多,但是,啊,但是,在函數上下文中的時候,函數裏邊的變量對象是活動對象,他的英文名字叫做 actiation object ,大面上看的意思就是說只有進入了這個執行上下文中的時候,也就是說執行到了這個函數的時候,其中的變量對象纔會被激活,纔會能被訪問,在沒有執行到這個函數的時候,其屬性是不能訪問的,這裏是和全局上下文不同的。

函數執行過程


function foo(a) {
  var b = 2;
  function c() {}
  var d = function() {};

  b = 3;

}

foo(1);

首先看這段代碼,上邊也說了,函數執行有兩個階段創建階段和執行階段

首先進如執行上下文,進入創建階段

  • 首先形參,也就是調用的方法的時候傳進來的值,如果你傳了就是有值得,如果沒傳就是一個undefined,相應得函數裏邊會有一個arguments對象,存放着形參得值,
  • 然後函數裏邊聲明得變量,在創建階段得時候是沒有值得,會被賦值一個undefined。
  • 函數聲明會由名稱和對應值組成一個變量對象的屬性被創建,也就是上邊說的函數得指針,我是這麼理解得,因爲這個變量指向了這個函數,如果變量對象已經存在相同名稱的屬性,則完全替換這個屬性

上邊這段代碼在創建階段是這樣得

{
    arguments: {
        0: 1,
        length: 1
    },
    a: 1,
    b: undefined,
    c: reference to function c(){},
    d: undefined
}

然後函數的而執行階段,這個時候就該幹嘛幹嘛了,函數裏邊聲明的變量,賦值等等的會在這裏根據代碼,修改變量的值

{
    arguments: {
        0: 1,
        length: 1
    },
    a: 1,
    b: 3,
    c: reference to function c(){},
    d: reference to FunctionExpression "d"
}

得出一個結論,函數的執行上下文裏邊在初始化的時候只包含一個arguments對象,其他的屬性是沒有值的,爲了直觀一點 ,舉個例子

function foo() {
    console.log(a);
    a = 1;
}

foo(); 

function bar() {
    a = 1;
    console.log(a);
}
bar(); 

比如說這個在foo函數的上下文裏邊打印a, 但是foo 裏邊沒有用var聲明,下邊的a就找不到所以會打印一個 a is not defined。

但是第二個的話會打印一個1,因爲搭載因之前,全局對象裏邊已經有了a屬性

最後就是,在上文提到

    c: reference to function c(){},
    d: reference to FunctionExpression "d"
    

在上下文創建的時候,變量是不會覆蓋這種聲明的,比如說


console.log(foo);
function foo(){
    console.log("foo");
}

var foo = 1;

會打印這個函數,但是, 啊,但是,如果是這樣

function foo(){
    console.log("foo");
}

var foo = 1;
console.log(foo);

這樣的話就變成了剛纔所說的賦值了 ,會打印1

以上是我對js函數的執行與上下文的一些認識,剛從博客園搬過來,有不足的希望指正

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