JavaScript 設計模式與開發實踐 - Chapter 2

Chapter 2

一般在物件導向中,我們知道 this 是指向到一個類別,但是在 JavaScript 中,this 指向的是一個物件, 而實際上到底是哪個物件,它是基於 function 執行時所執行的環境所綁定的,並不是 function 被宣告時當下的環境。

this 的指向可以分為四種:

  1. 作為物件的呼叫方法。
  2. 作為普通 function 的呼叫。
  3. 建構子的呼叫。
  4. Function.prototype.callFunction.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.callFunction.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));

透過 applycall 這兩個方法,可以改變 function 內 this 的指向,有時候在寫程式會不小心把 this 所指向的地方改掉了,造成一些執行錯誤,applycall 可以幫忙我們改善這個問題。

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