JavaScript 核心 - this 到底是誰


Posted by ai86109 on 2020-09-30

講了這麼久,終於可以來講 this 這個大魔王了


物件導向中的 this

在物件導向中,this 就代表現在對應到的 instance

class Dog{
  setName(name){
    this.name = name
  }
  sayHello(){
    console.log(this.name + ': hello')
  }
}

const yoyo = new Dog(‘yoyo')
yoyo.sayHello()

像是上面這個 this,指的就是 yoyo


其他地方的 this

那在不是物件導向的地方使用 this

基本上就會是預設值,依照執行環境而有所不同

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

test()

例如在 Node.js,這個 this 就是 global

在瀏覽器,這個 this 就是 window

但在嚴格模式下(最前面加上 'use strict’;),不論執行環境,this 都是 undefined。

-
但有幾種情況例外

(1) 在使用 DOM 元素時,this 就會是你點的按鈕

document.querySelector('.btn').addEventListener('click', function() {
  console.log(this)
})

(2) 使用 call & apply 呼叫 function 的時候

前面說過用 .call 去呼叫 function,帶入的第一個參數,可以改變 this

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

test.call(123)

apply 也和 call 有一樣的功能,差別只在於後面帶入的參數要用陣列

function test(a, b, c) {
  console.log(this)
  console.log(a, b, c)
}

test.call(123, 1, 2, 3)
test.apply(123, [1, 2, 3])

this 跟如何被呼叫有關

有趣的是,this 的值不在於他在程式碼的哪裡,而是和 function 如何被呼叫有關。

用以下程式碼舉例

const obj = {
  a: 123,
  test: function(){
    console.log(this)
  }
}

obj.test()

這邊的 this 是 obj

那如果換一種呼叫方式

var func = obj.test
func()

這邊的 this 卻是 undefined

提供一個有趣判斷 this 的解法

obj.test() 可以看成 obj.test.call(obj) => this 就是 obj

obj.inner.test() 可以看成 obj.inner.test.call(obj.inner) => this 就是 obj.inner

那剛剛的 func() 可以看成 func.call() => this 因為沒傳東西進去就會是 undefined


固定 this

那有辦法固定 this 的值嗎?有,使用 bind

剛剛我們說到

var func = obj.test
func()

this 會得到 undefined

但如果我們改寫成

var func = obj.test.bind(‘aabbcc’)
func()

此時的 this 就會被我們綁定為 aabbcc

之後就算我們用 call or apply 都無法去改變 this 的值。


this 的特例 again?

最後要來講一個特例

先看個程式碼

class Test{
  run() {
    console.log('run this:', this)
    setTimeout(function() {
      console.log(this)
    }, 100)
  }
}

const t = new Test()
t.run()

第一個 this 是 t,沒什麼問題
第二個 this,只是一般執行 function,所以如果用瀏覽器就是 window

但如果換一個寫法,換成 arrow function

class Test{
  run(){
    console.log('run this:', this)
    setTimeout(() => {
      console.log(this)
    }, 100)
  }
}

const t = new Test()
t.run()

就會發現第二個 this 也變成 t 了!

arrow function 的 this 會使用定義時的 this,所以就會跟第一個 this 一樣是 t,在使用時也要特別注意。


更多的 this 可以看 Huli 大的:淺談 JavaScript 頭號難題 this:絕對不完整,但保證好懂
或是What's THIS in JavaScript ?系列文,共三篇


#this #javascript







Related Posts

Go 起手式之一

Go 起手式之一

[ java ] JDBC 連線

[ java ] JDBC 連線

[ 筆記 ] 後端基礎 - 資料庫、SQL 語法

[ 筆記 ] 後端基礎 - 資料庫、SQL 語法


Comments