[ js 筆記 ] this 是什麼東西?能吃嗎?


Posted by Akira on 2022-03-17

剛開始學 Javascript 的人,一定跟我一樣,不知道this到底在做什麼?即便現在,我還是不是很明白什麼情況該 this,但就算不明白,我們還是可以先了解,this 到底指向什麼東西。

MDN 上寫說:
this 值由被呼叫的函式來決定。它不能在執行期間被指派,每次函式呼叫調用的值也可能不同。

我們要先知道,this 不會永遠指向同一個東西,會取決於函式被呼叫的方式及環境。

在全域環境執行,或直接呼叫函式 this 會指向全域

// 全域環境執行
console.log(this) // window

// 直接呼叫函式
function foo(){
    console.log(this)
} // undefined

全域環境執行中執行,不管是否是嚴格環境,都會顯示 window。
直接呼叫函式在嚴格模式中會顯示 undefined ,非嚴格模式會顯示 window。

使用物件來調用 this,this 會指向該物件。

let introduce = {
  name: "Chloe",
  greeting: function() {
    console.log('Hi, my name is', this.name)
  }
}

introduce.greeting() // Hi, my name is Chloe

調用 introduce.greeting() 的時候,.greeting()是作用在 introduce 的環境中,因此 this 會指向 introduce 這個物件。
但如果使用間接呼叫的話,this 就會退回 global 的環境。我們來看看以下的例子。

let introduce = {
  name: "Chloe",
  greeting: function() {
    console.log('Hi, my name is', this.name)
  }
}

let sayHi = introduce.greeting
sayHi() // Hi, my name is undefined

因為sayHi()是直接在 global 環境中呼叫,因此this會指向 global 。

可以使用 apply/call/bind 來綁定 this

透過 apply/call/bind 的方法來強制指定我們要的 this 是什麼。
我們同時看看 call 和 apply 的用法:

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

call 和 apply 的用法很像,傳出來的都是 function 執行的結果。

  • thisArg:要傳進去的 this 是誰
  • arg1,arg2,arg3:要帶進 function 的參數

唯一差別是 apply 參數傳入的方式是陣列。

const people = {
  name: "Chloe",
}

function introduce(age,like) {
  console.log(
`Hi, my name is ${this.name},
I am ${age} years old.
I like ${like}.`)
}

introduce.call(people,18,'apple')
introduce.apply(people,[18,'apple'])
// Hi, my name is Chloe,
// I am 18 years old.
// I like apple.

call 和 apply 的 this 還是有可能被改變,而 bind 則是硬繫結,綁定之後的 this 就沒辦法在更改。另外,bind 會回傳一個綁定好的函式。

const people = {
  name: "Chloe",
}

function introduce(age,like) {
  console.log(
`Hi, my name is ${this.name},
I am ${age} years old.
I like ${like}.`)
}

let speeking = introduce.bind(people,18,'apple')
speeking()
// Hi, my name is Chloe,
// I am 18 years old.
// I like apple.

this 會指向使用 new 建立的實體物件

let name = 'global'

class People {
  constructor(name) {
    this.name = name;
  }

  sayHi() {
    console.log(`Hi, my name is ${this.name}.`);
  }
}

let newPeople = new People('chloe')
newPeople.sayHi()

使用箭頭函式讓 this 指向函式環境

let introduce = {
  name: "Chloe",
  greeting: function() {    
    const arrow = () => {
      updateName()
      console.log('Hi, my name is', this.name)
    }  
    const updateName = ()=> {
      this.name = 'Amy'
    }
    arrow()
  }
}

introduce.greeting() // Hi, my name is Chloe

執行arrow()的環境是在greeting()下,因此arrow()的環境就是greeting()的 this,因此 this.name 會指向 introduce 中的 name。

為什麼要用 this?

在越複雜的環境,如果傳入明確的參數的話,通常會比 this 的執行環境更加複雜。

參考資料:
JavaScript this 用法整理
this 是什麼? – 談談JavaScript的this
JavaScript 中的 this 是什麼?
MDN-this


#javascript







Related Posts

React(13) - useContext & context API

React(13) - useContext & context API

Whack A Mole Game

Whack A Mole Game

[ 紀錄 ] 實戰練習 - Todo List ( 以 JS 實作前端 + PHP 後端 )

[ 紀錄 ] 實戰練習 - Todo List ( 以 JS 實作前端 + PHP 後端 )


Comments