Skip to content

誰是 this ?

簡單說

  • 誰調用了包含 this 的函式,誰是就 this !
  • 呼叫 函式 的環境,就是 this

全域環境

全域 環境下 this 等於 全域物件 (this === window)

js
// 在網路瀏覽器中,window 物件也是全域物件
console.log(this === window) // true

// 全域變數 a 賦值
var a = 123 // this.a = 123 一樣意思
console.log(window.a) // 123

函式環境

呼叫 函式 的環境,就是 this !

js
function sayThis() {
  return this
}

瀏覽器 / Node

  • this 就是 window (全域物件)
  • this 就是 global (全域物件/對象)
js
// 瀏覽器
sayThis() // window

// node
sayThis() // global

嚴格模式

嚴格模式 的情況下,會禁止 this全域物件,這時 this 若為 全域物件 就會顯示 undefined

js
'use strict'
function sayThis() {
  console.log(this)
}

sayThis() // undefined

物件環境

圖片出處: 卡斯伯's Blog

物件內 函式this 會指向執行時所屬的物件 本身。下面的例子 this 就是分別為呼叫函式的物件 person1person2

js
function getGender() {
  return this.gender
}

let person1 = {
  gender: 'male',
  getGender: getGender
}

let person2 = {
  gender: 'female',
  getGender: getGender
}

// (this === person1)
person1.getGender() // male 

// (this === person2)
person2.getGender() // female 

如果有多層 函式this 都是指向上一層!

js
function sayMyName() {
  console.log(this.name)
}

const person = {
  name: 'nike',
  age: 34,
  sayName: sayMyName,
  children: {
    name: 'niki',
    age: 6,
    sayName: sayMyName
  }
}

// ↓ this === person
person.sayName() // nike

//        ↓ this === children
person.children.sayName() // niki

呼叫函式的環境 決定 this

js
var name = 'out'

function sayName() {
  console.log(this.name)
}

const person = {
  name: 'in'
}

person.sayName = sayName

// 呼叫函式的環境是 `person`
person.sayName() // in 

// 呼叫函式的環境是 `window` (全域物件)
sayName() // out 

間接呼叫

承上,一般操作 person.sayName() 就會視 personthis;但如果將 person.sayName 賦與給 全域變數 a,再經由 全域變數 來呼叫 函式 ,那函式的呼叫環境,就是 「全域物件 window」。

🔰 呼叫函式的環境 決定 this !!

js
person.sayName() // in 

const a = person.sayName
a() // out

脫離物件的 this

fun1 函式中的 this 就是指向 person 就如之前的理解, 但 fun2thiswindow,就與認知不同了。

js
const person = {
  name: 'nike',
  fun1: function() {
    console.log(this === person) // this 指向 person
    let fun2 = function() {
      console.log(this === person) //  this 指向 window
    }
    fun2()
  }
}

person.fun1() // true false

「脫離了物件, this 的值就沒什麼意義」

淺談 JavaScript 頭號難題 this:絕對不完整,但保證好懂

DANGER

函式 (含 this) 脫離 物件 時, this 就是 全域物件

箭頭函式的 this

箭頭函式不擁有 this 特性,會指向 全域物件

js
var name = 'out'

const person = {
  name: 'in',
  sayName: () => {
    console.log(this.name)
  }
}

person.sayName() // out

指定 this

嚴格模式 下,this 若指向 全域物件 則為 undefined

js
'use strict'
function person(age, count) {
  console.log(this, age, count)
}

person(34, 4000) // undefined 34 4000

call

定義函式執行時的 this 值,同時傳入 參數MDN

fun.call(thisArg[, arg1[, arg2[, ...]]])

  • thisArg 操作 fun 函式時,指定的 this
  • arg1 … 其它參數
js
person.call(undefined, 34, 3000) // undefined 34 3000
person.call({name: 'nike'}, 34, 3000) // {name: 'nike'} 34 3000

範例

一般來說 sayName2 函式執行的 this 會是 window 全域物件,但可以使用 call 來指定 this

js
const person = {
  name: 'nike',
  age: 34,
  sayName: function() {
    console.log(this.name)

    let sayName2 = function() {
      console.log(this)
    }
    sayName2() // window
    sayName2.call(this) // 把 person 傳入當 this
  }
}

person.sayName() 
// nike  window  {name: 'nike', age: 34, sayName: ƒ}

apply

這個操作與 call 其本上是全部相同,只差別在 參數 要使用 陣列 來傳入。 MDN

fun.apply(thisArg, [argsArray])

  • thisArg 操作 fun 函式時,要傳入的 this
  • argsArray 其它參數,使用 陣列 傳入
js
person.apply(undefined, [34, 4000]) // undefined 34 4000
person.apply({name: 'niki'}, [34, 4000]) // {name: 'niki'} 34 4000

bind

call 操作方式 87 分像,只是 bind 會回傳一個綁定好 this函式,待後續執行。 MDN

fun.bind(thisArg[, arg1[, arg2[, ...]]])

  • thisArg 要綁定的 this
  • arg1 ... 要傳入的參數
js
const bindPersonThisFun = person.bind(undefined, 34, 4000) 
bindPersonThisFun() // undefined 34 4000

const bindPersonThisFun2 = person.bind({name: 'nike'}, 34, 4000) 
bindPersonThisFun2() // {name: 'nike'} 34 4000

何時會使用到綁定?

1. 物件屬性方法內再宣告,有 this 函式

此時宣告的函式內 this全域物件 就不再是這個物件,可以使用 綁定 this 來解決這個問題。

js
const person = {
  name: 'nike',
  fun1: function() {
    console.log(this === person) // this 指向 person
    let fun2 = function() {
      console.log(this === person) //  this 指向 window
    }
    fun2()
  }
}

2. 建構函式的方法函式內再宣告,有 this 函式

函式內再宣告,有 this 的函式,這個 this 會指向 全域變數

js
class Person {
  constructor(name) {
    this.name = name
  }

  sayName() {
    console.log(this.name)
  }

  sayNameAgin() {
    setTimeout(function() {
      console.log(this.name)
    }, 1000)
  }
}

const niki = new Person('NIKI')
niki.sayName() // NIKI
niki.sayNameAgin() // undefined

解決方法:

  • 使用 箭頭函式
    js
     setTimeout(() => {
        console.log(this.name)
      }, 1000)
    
  • 使用 綁定 this 方法
    js
    setTimeout(function() {
      console.log(this.name)
    }.bind(this), 1000)
    

參考:

Reference