
JavaScript中除了基本型別(String/Number/Boolean等),其他型別(Array/Object/Data)實際上都是特定物件延伸而來,這些個特定物件裡面都有自帶的原型,可以稱它為prototype。
當建立一個新的物件時,它的隱藏__proto__會自動被指到ptototype,因此這個物件才能夠任意使用prototype定義好的函式、屬性 => 我們稱之為「原形鏈」。
let arr = new Array()
arr.__proto__ === Array.prototype // true
bind、call、apply三者都是JavaScript Object 的方法
使用 apply 和 call,可以直接決定並執行一個函數,並告訴它 this 應該是什麼。bind 不會馬上執行函數,而是會給一個新的函數,當這個新的函數被執行時,它會知道 this 應該是先前指定的那個值。
bind 可以綁定一個函數的 this 值,使用 bind 建立一個新的函數時,無論這個新函數在哪裡被呼叫,它的 this 值都會被固定在指定的物件上。
let calculator = {
factor: 2,
multiply: function(number) {
return this.factor * number;
}
};
let double = calculator.multiply;
console.log(double(3)); // 會輸出: NaN,因為 this 現在是全域物件或 undefined
加上bind來修正 this 指向
let fix = double.bind(calculator);
console.log(fix(3)); // 正確輸出 6
範例程式碼中:
1.先從calculator中取出multiply然後賦予值到double函式
2.在全域呼叫了double函式,因此this會指向全域,而不是calculator
3.全域中找不到multiply,因此會回傳全域物件(非嚴格模式)或是 undefined(嚴格模式)
4.undefined * 3 進行運算會回傳 NAN
(加上bind修正)
5.建立一個新函數fix,將double函數的this值綁定到calculator物件上
6.fix之後在哪邊呼叫,它的this都會是固定指向calculator
把call和apply放在一起講的原因是它們極為相似
最大的不同是 call 接受一連串的參數,而 apply 接受一組陣列形式的參數 --MDN
const restaurant = {
name: "Tasty Restaurant",
bill: function(food, drink) {
console.log(`Bill from ${this.name}:`);
console.log(`Food: ${food}`);
console.log(`Drink: ${drink}`);
}
};
const cafe = {
name: "Cozy Cafe"
};
// 使用 call 來為 cafe 印出bill
restaurant.bill.call(cafe, "Sandwich", "Coffee");
// 輸出:
// Bill from Cozy Cafe:
// Food: Sandwich
// Drink: Coffee
// 使用 apply 來為 cafe 印出bill
restaurant.bill.apply(cafe, ["Croissant", "Latte"]);
// 輸出:
// Bill from Cozy Cafe:
// Food: Croissant
// Drink: Latte
restaurant.bill.call(cafe, "Sandwich", "Coffee")的作用是調用restaurant的bill方法,然後將 this 值指到 cafe,所以我們只要調用restaurant方法,輸出的name名稱即會是cafe
基本上apply跟call的執行方式是一樣的,相較於call不同的是,apply第二個參數是帶入一個Array
以apply做詳細的說明:
1.apply 方法的第一個參數設定指到 this 值的物件,在範例中,我們選擇了 cafe 作為 this 值
2.apply第二個參數帶入一個Array,這邊帶入「["Croissant", "Latte"]」做為參數,傳遞給bill函數
3.當bill的方法被執行時,他的this值是指向cafe,這樣this.name就會輸出"Cozy Cafe"
call
apply

參考文章
JavaScript - call,apply,bind
Function.prototype.bind()
Function.prototype.call