38

JS 底層觀念 - this 物件 下(this 綁定控制)

深入探討 JavaScript 中 this 的五種綁定方式(預設綁定、隱式綁定、顯式綁定、new 綁定、箭頭函式綁定),透過範例說明它們的綁定邏輯與優先順序,幫助你理解在不同情境中 this 的指向,並掌握常見陷阱與實務應用技巧。

2025/06/25


前情提要

📚 this 的 5 種綁定方式

類型專有名詞(Binding Type)綁定邏輯說明範例
1️⃣ 預設綁定Default Binding函式直接呼叫 → this = window / globalsayHi()
2️⃣ 隱式綁定Implicit Binding被物件呼叫 → this = 該物件obj.sayHi()
3️⃣ 顯式綁定Explicit Bindingcall / apply / bind 明確設定 thissayHi.call(obj)
4️⃣ new 綁定New Binding建構函式內 → this 是新創建的物件new Person()
5️⃣ 箭頭綁定Lexical Binding箭頭函式固定綁定「定義當下」的作用域() => this.name

上篇提到了1、2,這篇要來介紹剩下的this綁定

3️⃣顯式綁定(Explicit Binding)

方法立即執行可傳入參數用途
call逐一傳入立即調用,改變 this
apply陣列傳入立即調用,適合參數不固定
bind逐一傳入不會立即執行,回傳新函式
const person = { name: "Alice", greet: function (greeting, punctuation) { console.log(`${greeting}, I'm ${this.name}${punctuation}`); }, }; const otherPerson = { name: "Bob", }; // call:立即執行,參數逐個傳入 person.greet.call(otherPerson, "Hello", "!"); // → Hello, I'm Bob! // apply:立即執行,參數用陣列傳入 person.greet.apply(otherPerson, ["Hi", "!!"]); // → Hi, I'm Bob!! // bind:不會執行,回傳一個綁定後的新函式 const boundGreet = person.greet.bind(otherPerson, "Hey", "!!"); boundGreet(); // → Hey, I'm Bob!!

簡單來說bind使用時是定義一個新function,與原來function不同的地方在於指定了this為某個物件。

call & apply都是使用function時指定this,差別在於

  • call 接收逐個參數
  • apply 接收參數陣列

bind綁定this範例情境:

function Button(callback) { // 模擬點擊 callback(); // 這裡callback為預設綁定若沒有bind,this指向window } const app = { name: "MyApp", clickHandler() { console.log(`${this.name} was clicked`); }, sayHello() { console.log(`hello ${this.name}!`) } }; Button(app.clickHandler.bind(app)); // 如果不 bind,this 是 undefined setTimeout(app.sayHello.bind(app),1000); // callback需bind this

在需要將function作為參數傳入時(callback),就會需要綁定,否則你就算傳入時前面有所屬物件,再傳入後this仍然會丟失。

call、apply綁定this範例情境

function printFullName(preMessage) { console.log(`${preMessage} ${this.firstName} ${this.lastName}`); } const user1 = { firstName: "Ada", lastName: "Lovelace", }; const user2 = { firstName: "Pizza", lastName: "6inch", } printFullName.call(user1,"Hi"); // → Hi Ada Lovelace printFullName.apply(user2,["Hi"]) // -> Hi Pizza 6inch

呼叫第三方函式或工具時,需要在call function時,根據情境改變不同this時可使用call/apply。

4️⃣new 綁定(New Binding)

當你使用 new 關鍵字來呼叫一個函式時,該函式就會被當作建構函式(constructor function),此時this綁定就會是建立出來的「新物件」本身

function Person(name) { this.name = name; // 如果有new,此時this綁定至user } const user = new Person("Ada"); console.log(user.name); // Ada const user = Person("Ada"); // 如果沒有 new console.log(user); // undefined console.log(window.name); // "Ada"(非嚴格模式下被綁到 window)

5️⃣ 箭頭函式綁定(Lexical Binding)

箭頭函式的最大特性之一就是:

它不會擁有自己的 this,而是繼承定義時外層作用域的 this 值(靜態綁定)

這跟一般的函式不同。一般函式的 this 是執行時決定的;而箭頭函式的 this 是定義時就決定好了

  • 因為這個特性所以我在刷題常常中招時QQ
  • 箭頭函式我已經習慣使用到完全不知道跟傳統function差在哪裡XD
const obj = { name: "Alice", greet: function () { // sayHi 為 arrow function // 宣告時綁定this為obj const sayHi = () => { console.log(`Hi, I'm ${this.name}`); }; sayHi(); // 即使沒有obj.在前,也綁定到this }, }; obj.greet(); // Hi, I'm Alice

傳統函式會導致 this 丟失

const obj = { name: "Bob", greet: function () { // 傳統function const sayHi = function () { console.log(`Hi, I'm ${this.name}`); }; sayHi(); // 這裡為預設綁定 this===window }, }; obj.greet(); // Hi, I'm undefined

實務場景

事件處理時保持 this 一致

class Button { constructor(label) { this.label = label; this.handleClick = () => { console.log(`Button: ${this.label}`); }; } } const btn = new Button("Submit"); document.querySelector("button").addEventListener("click", btn.handleClick);

若這裡不用箭頭函式,this 就會指向 button DOM 元素,導致錯誤。

綁定優先級

總共五種綁定方式,當同時兩種以上綁定方式衝突時,優先級如下

Default < Implicit < Explicit < new ≈ Arrow(互斥,優先級最高)

由於建構函式必須是傳統function,換句話說arrow function不能被new調用,所以不會發生bind衝突的情況。

  • 對arrow function、new fcuntion使用bind、call、apply綁定this無效
  • 對obj.function使用bind、call、apply會重新綁定this
  • 無任何綁定則this指向window

總結

最後總結將表格放在下面

📚 this 的 5 種綁定方式

類型專有名詞(Binding Type)綁定邏輯說明範例
1️⃣ 預設綁定Default Binding函式直接呼叫 → this = window / globalsayHi()
2️⃣ 隱式綁定Implicit Binding被物件呼叫 → this = 該物件obj.sayHi()
3️⃣ 顯式綁定Explicit Bindingcall / apply / bind 明確設定 thissayHi.call(obj)
4️⃣ new 綁定New Binding建構函式內 → this 是新創建的物件new Person()
5️⃣ 箭頭綁定Lexical Binding箭頭函式固定綁定「定義當下」的作用域() => this.name

此筆記參考了:kuro's BlogExplainThis、ChatGPT



留言區

發表留言