JavaScript上下文相關的總結

這裏主要記錄在平常中對知識的學習,經過結合筆記與自身理解的方式嘗試寫下總結
文章對細節可能不會一一介紹解釋,內容僅做參考
複製代碼

上次寫了做用域相關的知識總結,這篇文章是它的進一步提高。若是對做用域還不是很瞭解,能夠先看一下:JavaScript做用域相關的總結javascript

我翻了挺多文章,感受他們對上下文這個詞的解釋都有些抽象,不如干脆就放過他的字面意義,而是記住他是如何產生的,以及做用java

當JavaScript執行一段可執行代碼時,就會先創建對應的執行上下文app

執行上下文的代碼會分紅兩個階段進行:函數

  • 進入執行上下文(分析)
  • 代碼執行(處理)

在生成的每一個執行上下文中,都會有3個重要的屬性:post

  • 變量對象
  • 做用域鏈
  • this

1、變量對象

變量對象是與執行上下文相關的數據域,存儲了在上下文中定義的變量函數聲明學習

進入執行上下文時(未代碼執行),變量對象會進行初始化,包括:ui

  1. 函數的全部形參(arguments)
  2. 函數聲明
  3. 變量聲明

舉個栗子:this

function a(n, m) {
    var b = 1
    function c() {
        console.log('c')
    }
    var d = function() {
        console.log('d')
    }
    b = 2
}
a(10, 20)
複製代碼

在進入執行上下文後,此時的變量對象是這樣的:spa

變量對象 = {
    arguments: {
        0: 10,
        1: 20,
        length: 2
    },
    n: 10,
    m: 20,
    b: undefined,
    c: function, d: undefined } 複製代碼

等到了代碼執行時,代碼會順序執行,從而更改變量對象的值。當代碼執行到最尾時,變量對象是這樣的:code

變量對象 = {
    arguments: {
        0: 10,
        1: 20,
        length: 2
    },
    n: 10,
    m: 20,
    b: 1 -> 2,
    c: function, d: functionExpression } 複製代碼

2、做用域鏈

在函數中,當查找變量的時候,會先從當前上下文的變量對象中查找,若是沒有找到,就會從父級(詞法層面)執行上下文的變量對象查找,一直找到全局上下文的變量對象。這樣由多個執行上下文的變量對象構成的鏈表就叫作做用域鏈

做用域總結中已經提過,對於一個變量的查找方向是在做用域定義的時候就已經約定好的


3、this

JavaScript有一套不一樣於其餘語言的對this的處理機制。在五種不一樣的狀況下,this指向的各不相同

  • 全局範圍內 this - 指向全局對象
  • 函數調用 foo() - 指向全局對象
  • 方法調用 bar.foo() - 指向bar對象
  • 調用構造函數 new foo() - 指向新建立的對象
  • 顯式設置 apply/call - 指向函數第一個參數

常見誤解

Foo.method = function() {
    function test() {
        console.log(this)
    }
    test() // window
}
複製代碼

這裏會被認爲test函數中的this會指向Foo對象,實際上不是這樣子的,而是會指向全局對象。若是想拿到Foo的內部this,能夠這樣寫

Foo.method = function() {
    let that = this
    function test() {
        console.log(that)
    }
    test() // Foo
複製代碼

let a = {
    b: function() {
        console.log(this.c)
    },
    c: 1
}
let mb = a.b
mb() // undefined (指向window)
複製代碼

另外一個看起來奇怪的地方是函數別名,也就是將一個方法賦值給一個變量。上例中b 就像一個普通的函數被調用。所以,函數內的 this 不被指向到 a 對象,而是全局對象

4、總結

以上三個屬性構成了執行上下文的做用,使得在代碼執行時可以使用相關的特性

相關文章
相關標籤/搜索