Louis's blog
GitHub
GitHub
  • 瀏覽器運作原理
  • 閉包
  • this
  • arguments 和 array-like
  • apply、call、bind
  • 函式程式設計
  • 物件和原型
  • 原型鏈和繼承
  • ES6 和 Class
  • ES6 中新增的數據類型
  • ES6 語法糖
  • var、let、const
  • ES7~ES12
  • Strict Mode
  • 補充
  • Proxy 和 Reflect
  • Promise
  • Iterator
  • 生成器
  • async、await
  • Event loop
  • 錯誤處理
  • 模塊化
  • 套件管理工具
  • JSON
  • WebStorage
  • IndexDB
  • Cookie
  • BOM
  • DOM
  • 防抖(debounce)和節流(throttle)
  • Deep copy
  • 事件總線

this

常見的編程語言中,幾乎都有 this 關鍵字,但是 JavaScript 中的 this 和常見的物件導向語言中的 this 不太一樣,通常在 Java、C++等語言中需要有一個類才能透過 this 調用當前物件。

this 的作用

假設我們有以下的程式碼:

var obj = {
  name: 'louis',
  eating: function () {
    console.log(this.name + '在吃東西')
  }
}
obj.eating()

當我們執行這段結果後輸出會是:

louis在吃東西

也就是說使用 this.name 我們得到當前的物件的 name 屬性,不過沒有 this 也是可以編寫相對的程式碼,像是:

var obj = {
  name: 'louis',
  eating: function () {
    console.log(obj.name + '在吃東西')
  }
}
obj.eating()

不過這樣做當我們改變物件名稱時,內部方法就要跟著進行改變,少了 this 會缺少很多複用程式碼的機會。

this 在全局作用域中

一般來說當我們在瀏覽器中執行:

console.log(this)

我們會得到 window 物件,而在 Nodejs 中執行 this 時,會得到一個空物件,而之所以會是空物件,是 Nodejs 中使用 Commonjs 規範,將每個文件都視為一個獨立的 module,而在編譯後會將這個 module 放到一個函數中並且進行 call 綁定,而這個綁定的物件是 expots

所以在 Nodejs 中執行以下程式碼:

exports.obj = {
  foo: 'foo'
}

console.log(this)

會得到:

{ obj: { foo: 'foo' } }

this 在函數中

由於 this 並非在編譯階段中就進行綁定,而是在程式碼執行時動態綁定,所以有幾個綁定規則。

假設有以下這樣一個函數:

function foo() {
  console.log(this)
}

函數獨立被調用

如果直接在函數中進行調用,在瀏覽器中的輸出結果會是 window 物件:

foo()

以及

var obj = {
  foo: foo
}
var bar = obj.foo
bar()

以上兩種情況都是屬於獨立調用,所以輸出結果都會是全局 window 物件。

綁定在物件中調用

如果該函數是物件中的某個方法,輸出結果會是會是該物件:

var obj = {
  foo: foo
}
// 會得obj
obj.foo()

和前面的案例有一點類似,但是只要前面綁定有物件,輸出的結果都會是綁定在前面的物件。

使用函數原型中的方法進行綁定

在物件中做為方法調用可以讓函數具有指定的 this,如果不想要讓函數作為方法但是又想要指定 this,可以使用 call 或是 apply 對該函數中的 this 進行綁定:

// 會得到String {"abc"} 物件
foo.call('abc')

也可以使用 bind,前面有說到只要是函數獨立調用 this 就會指向全局 windon 物件,不過 bind 的優先級更高可以將獨立調用的函數綁定 this。

function foo() {
  console.log(this)
}
var newFoo = foo.bind('bar')
newFoo()

輸出的結果為 String 物件。

this 在透過構造函數(new)創建出來的物件中

JavaScript 可以使用 new 關鍵字進行函數的調用,而使用 new 創建出來的物件會直接將 this 和該物件進行綁定。

function Person(name, age) {
  this.name = name
  this.age = age
}

var p1 = new Person('why', 10)
console.log(p1.name, p1.age)

this 綁定規則的優先級

new 構造函數 > call/apply/bind > 作為物件中的方法調用 > 直接調用函數

this 與箭頭函數

箭頭函數(Arrow Function)不綁定任何 this,而是從外層作用域中尋找 this。

var foo = () => {
  console.log(this)
}
// 輸出為window
foo.call('bar')

箭頭函數常常用在非同步函數中獲取外層的 this 物件,例如:

var obj = {
  data: [],
  getData: function () {
    // 在箭頭函數之前的解決方案
    var _this = this
    setTimeout(function () {
      var result = ['aaa', 'fff', 'ddd']
      _this.data = result
    }, 2000)
  }
}
obj.getData()

有了箭頭函數可以直接調用外層的 this:

var obj = {
  data: [],
  getData: function () {
    setTimeout(() => {
      var result = ['aaa', 'fff', 'ddd']
      this.data = result
    }, 2000)
  }
}
obj.getData()
Edit this page
Last Updated:
Contributors: louis61619, louis
Prev
閉包
Next
arguments 和 array-like