Skip to content

2026-06-23

/ 15 分鐘閱讀

/ Deep JavaScript Foundations v3

隱式綁定與明確綁定:this 的前兩種規則 ​

本篇延續上一篇對 this 關鍵字的介紹。上一篇確立了核心原則:this 由呼叫方式決定,共有四種規則。本篇深入前兩種:隱式綁定(implicit binding)與明確綁定(explicit binding),並說明 this 遺失問題與硬綁定的使用取捨。

規則一:隱式綁定(Implicit Binding) ​

隱式綁定是四種規則中最常見、也最直覺的一種。規則很簡單:

this 指向呼叫該方法時,點號(.)左側的物件。

javascript
var workshop = {
    teacher: 'Kyle',
    ask(question) {
        console.log(this.teacher, question);
    },
};

workshop.ask('What is implicit binding?');
// Kyle What is implicit binding?

workshop.ask(...) 的呼叫點(call site)是 workshop.ask,點號左側是 workshop,因此 this 指向 workshop。

這個規則之所以直覺,是因為它的行為與其他語言的 this 最為相似:方法所屬的物件就是 this。

隱式綁定的實際用途:跨物件共享行為 ​

隱式綁定的真正價值在於,同一個函式可以被多個物件共享,而不需要為每個物件各自定義一份:

javascript
function ask(question) {
    console.log(this.teacher, question);
}

var workshop1 = { teacher: 'Kyle', ask: ask };
var workshop2 = { teacher: 'Suzy', ask: ask };

workshop1.ask('How do I share a method?');
// Kyle How do I share a method?

workshop2.ask('How do I share a method?');
// Suzy How do I share a method?

只有一個 ask 函式,但透過隱式綁定,它在 workshop1 和 workshop2 兩個不同的上下文中各自執行,得到各自的 this。這就是 this 系統提供動態彈性的具體體現。

規則二:明確綁定(Explicit Binding) ​

隱式綁定依賴呼叫點的寫法,有時我們需要更主動地控制 this 的指向。Function.prototype 上的 .call() 與 .apply() 提供了這個能力:

javascript
function ask(question) {
    console.log(this.teacher, question);
}

var workshop1 = { teacher: 'Kyle' };
var workshop2 = { teacher: 'Suzy' };

ask.call(workshop1, 'Can I explicitly set context?');
// Kyle Can I explicitly set context?

ask.call(workshop2, 'Can I explicitly set context?');
// Suzy Can I explicitly set context?

.call(thisArg, arg1, arg2, ...) 與 .apply(thisArg, [args]) 的第一個參數就是要指定的 this 上下文,差別只在於後續參數的傳遞方式。這裡我們明確告訴 JavaScript:「用這個物件作為 this 來呼叫這個函式。」

this 遺失問題(Losing the this Binding) ​

明確綁定的一個常見陷阱:把方法作為 callback 傳遞時,this 會遺失。

javascript
var workshop = {
    teacher: 'Kyle',
    ask(question) {
        console.log(this.teacher, question);
    },
};

setTimeout(workshop.ask, 10, 'Lost this?');
// undefined Lost this?

setTimeout 接收到的是 workshop.ask 這個函式的參考,而非 workshop.ask 這個呼叫。當計時器觸發時,呼叫點大約等同於 cb.call(window, ...),this 被綁定到全域物件(瀏覽器中是 window),不是 workshop,因此 this.teacher 是 undefined。

這個問題的根本原因是:傳遞的是函式本身,與它原本的物件脫鉤了。

硬綁定(Hard Binding):.bind() ​

解決 this 遺失的常見方案是 .bind():

javascript
setTimeout(workshop.ask.bind(workshop), 10, 'Hard bound this?');
// Kyle Hard bound this?

.bind() 不會立即呼叫函式,而是回傳一個新的函式,這個新函式無論被誰呼叫、以何種方式呼叫,this 永遠固定指向指定的物件。這就是「硬綁定」的名稱由來:把 this 鎖死。

彈性 vs 可預測性:工具選擇的判斷框架 ​

Kyle Simpson 在這裡提出了一個重要的設計取捨:

  • this 系統的價值在於動態彈性:同一個函式能在不同上下文中重用
  • .bind() 把這個彈性抹除:換來可預測性,但也放棄了 this 系統的核心優勢

如果你的程式碼大量使用 .bind(),這是一個信號:你可能正在用錯誤的工具解決問題。Kyle Simpson 的判斷啟發如下:

如果大多數呼叫點都需要硬綁定,你付出了撰寫 this aware 程式碼的代價,卻沒有得到動態彈性的好處。此時應該改用閉包與詞彙範疇,寫出可預測的程式碼。

.bind() 本身不是壞東西,偶爾使用是合理的取捨。但如果發現頻繁使用它,值得重新思考這段程式碼是否適合用 this 系統來設計。

複習 ​

隱式綁定規則如何決定 this 的指向? ​

在隱式綁定中,this 指向呼叫該方法時點號左側的物件,即呼叫點所使用的物件。

.call() 和 .apply() 在函式呼叫中有什麼用途? ​

兩者都允許在呼叫函式時,明確指定 this 的上下文,方式是將目標上下文物件作為第一個參數傳入。

「this 遺失」問題在傳遞函式時會造成什麼狀況? ​

當函式被作為 callback 傳遞到其他上下文時,它可能與原本的物件脫鉤,導致 this 被重新綁定到其他物件(通常是全域物件)。

.bind() 方法在 JavaScript 中的作用是什麼? ​

.bind() 建立並回傳一個新函式,無論該函式以任何方式被呼叫,this 都永遠固定指向指定的上下文物件。

若頻繁使用 .bind(),建議採取什麼做法? ​

頻繁使用 .bind() 可能代表應該改用詞彙閉包(lexical closure),以獲得更自然、更可預測的行為。

小測驗 ​

`this` 指向物件的主要規則是哪一種? 隱式綁定(implicit binding)
哪個方法可以在呼叫函式時明確指定其上下文? .call() 或 .apply()
`.bind()` 方法解決了什麼問題? 建立一個擁有固定 `this` 上下文的新函式
使用 `this` 關鍵字最主要的優勢是什麼? 能夠跨不同上下文共享同一個函式的行為
在什麼情況下應該考慮從 `this` aware 程式碼改用詞彙閉包? 當大多數呼叫點都需要使用硬綁定(.bind())時

此文章是 FrontendMasters 上的 Deep JavaScript Foundations, v3 課程筆記

最後更新時間:

Buy Me A Coffee

系列章節 第 57 篇 / 共 69 篇

0 %
MIT Licensed | Copyright © 2025-present Wen-Hsiu's Blog
Photo by Federica Galli on Unsplash