this 關鍵字與原型鏈
this 是什麼?
this 指向「誰在呼叫這個函式」。 它不是在定義時決定的,而是在呼叫時才決定。
this 的四種綁定規則
// 1. 預設綁定 — 全域呼叫
function sayHi() {
console.log(this);
}
sayHi(); // ← 瀏覽器中 this = window(嚴格模式下 undefined)
// 2. 隱式綁定 — 被物件呼叫
let user = {
name: "小明",
greet() {
console.log(this.name); // ← this = user(呼叫者)
}
};
user.greet(); // ← "小明"
// 3. 顯式綁定 — call / apply / bind
function greet(greeting) {
console.log(`${greeting}, ${this.name}`);
}
let person = { name: "小華" };
greet.call(person, "你好"); // ← "你好, 小華"(this = person)
greet.apply(person, ["哈囉"]); // ← "哈囉, 小華"(參數用陣列)
let bound = greet.bind(person); // ← 回傳新函式,this 永遠是 person
bound("嗨"); // ← "嗨, 小華"
// 4. new 綁定 — 建構函式
function User(name) {
this.name = name; // ← this = 新建立的物件
}
let u = new User("小美");
console.log(u.name); // ← "小美"
箭頭函式的 this
// ⚠️ 箭頭函式沒有自己的 this,它繼承外層的 this
let user = {
name: "小明",
// ❌ 箭頭函式:this 不是 user
greetArrow: () => {
console.log(this.name); // ← this = 外層(可能是 window)
},
// ✅ 一般方法:this 是 user
greetNormal() {
console.log(this.name); // ← this = user
},
// ✅ 箭頭函式在方法「裡面」很好用
delayGreet() {
setTimeout(() => {
console.log(this.name); // ← this 繼承外層的 this = user ✅
}, 1000);
}
};
原型鏈(Prototype Chain)
// 每個物件都有一個隱藏的 __proto__ 屬性
let animal = {
eat() { console.log("吃東西"); }
};
let dog = {
bark() { console.log("汪汪"); }
};
// 設定 dog 的原型為 animal
Object.setPrototypeOf(dog, animal);
dog.bark(); // ← "汪汪"(自己有)
dog.eat(); // ← "吃東西"(從原型找到的)
// 原型鏈:dog → animal → Object.prototype → null
Class 的原型本質
class Animal {
constructor(name) {
this.name = name; // ← 實例屬性
}
eat() { // ← 原型上的方法
console.log(`${this.name} 在吃東西`);
}
}
class Dog extends Animal {
bark() {
console.log(`${this.name} 汪汪`);
}
}
let dog = new Dog("旺財");
// 原型鏈:
// dog → Dog.prototype → Animal.prototype → Object.prototype → null
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true
console.log(dog instanceof Object); // true
💡 JavaScript 的 class 只是原型繼承的語法糖,底層還是原型鏈。