JavaScript 設計模式與開發實踐 - Chapter 2
JavaScript `this`, `call`, `apply`.
Chapter 2
一般在物件導向中,我們知道 this 是指向到一個類別,但是在 JavaScript 中,this 指向的是一個物件,
而實際上到底是哪個物件,它是基於 function 執行時所執行的環境所綁定的,並不是 function 被宣告時當下的環境。
this 的指向可以分為四種:
- 作為物件的呼叫方法。
- 作為普通 function 的呼叫。
- 建構子的呼叫。
Function.prototype.call和Function.prototype.apply的呼叫。
接下來透過範例來了解這四種呼叫方式:
作為物件的呼叫方法
const obj = {
name: 'pj',
sayHi: function () {
console.log(this === obj); // true
console.log(`Hi, ${this.name}`); // pj
},
};
作為普通 function 的呼叫
當 function 不作為物件被呼叫時,也就是普通 function,這時候的 this 指向的是全域物件,在 JavaScript 中指的就是 window。
window.name = 'pj';
const sayHi = function () {
return `Hi, ${this.name}`;
};
console.log(sayHi()); // pj
建構子呼叫
const P = function {
this.name = 'pj';
};
const p = new P();
console.log(p.name) // pj
另一個特別的情況是:
const P = function () {
this.name = 'pj';
return {
name: 'other people',
};
};
const p = new P();
console.log(p.name); // other people
所回傳的並不是我們原本所給的 this.name,而是一個物件。
Function.prototype.call 和 Function.prototype.apply
Function.prototype.call 和 Function.prototype.apply 兩者的方式其實差不多,第一個參數都是傳入 function 內的 this,差別在於後面第二個所接受的參數不同,更多請參考 JavaScript MDN。
這兩個方法可以動態的去改變傳入 function 的 this:
const obj1 = {
name: 'obj1',
getName: function () {
return `obj1: ${this.name}`;
},
};
const obj2 = {
name: 'obj2',
getName: function () {
return `obj2: ${this.name}`;
},
};
console.log(obj1.getName.call(obj2));
透過 apply 和 call 這兩個方法,可以改變 function 內 this 的指向,有時候在寫程式會不小心把 this 所指向的地方改掉了,造成一些執行錯誤,apply 和 call 可以幫忙我們改善這個問題。
Function.prototype.bind
在 Reactjs 中還蠻常用到 bind 這個方法,其實 bind 的實作也是利用了 apply 的功能,下面範例是一個簡單的實作:
Function.prototype.bind = function (context) {
var self = this;
return function () {
return self.apply(context, arguments);
};
};
const obj = {
name: 'pj',
};
const myFunc = function () {
console.log(this.name);
}.bind(obj);
myFunc(); // pj