JavaScript 設計模式與開發實踐 - Chapter 2
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) // trueconsole.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