JavaScript 物件導向

  • Why JavaScript OO
  • JavaScript Prototype
  • Prototype Chain
  • Prototypal Classes
  • Pseudoclassical Pattern
  • Superclass and Subclass
  • Pseudoclassical Subclass

Why JavaScript OO:

當有多個 object 都擁有相同或類似的 property 時,我們就可以透過 JS 物件導向 (object oriented) 的方式盡可能的 reuse 相同的程式碼,減少程式碼的複製以及記憶體的使用。

例如:我們要製作一個網頁賽車遊戲,這個時候在 JS 中我們會需要有不同的object 記錄每一個車子的位置,而每一個物件都會需要有移動(move)的 function。

JavaScript Prototype

首先,我們先來了解什麼是 JavaScript Prototype,根據定義:

所有的 JavaScript 物件都有一個 prototype,每一個物件都會從他們的 prototype 中繼承(inherit)一些特性 (properties) 和方法(methods)。而 prototype 本身也是一個物件,

Prototype Chain

Prototype Chain 概念圖 / 取自 Udacity

接著,我們來介紹 Prototype Chain 這個詞,什麼是 Prototype Chain 呢?假設我們已經有了一個 objA ,我們透過 Object.create 這個 function,可以新增一個 objB。

The Object.create() method creates a new object with the specified prototype object and properties.

這個時候由於 Object.create 新增出來的 objB 會是基於 objA 的屬性和原型產生。

所以如果接下來我們再於 objA 新增一個屬性,例如 objA.z = 3 ,當我們透過 objB 呼叫這個屬性時會發生什麼事呢?由於 objB 本身並沒有這個屬性,所以程式會再去查看 objB 的原型是否有這個屬性,這種機制就是基於 Prototype Chain。

範例程式碼:

// 新增 objA
var objA = { a: 1 };
var objB= Object.create(objB);
objA.z = 3;
console.log(objB.z);  // 3

Prototypal Classes

為什麼使用 Prototypal Classes? 以下範例程式碼是一個以 Object Decorator Pattern 達到重複使用 Car function 的範例,然而於下面的範例中,每一次新增的 Car 物件(例如 var ben = Car(2), var amy = Car(3)),都會在記憶體中產生新的 obj.move function,造成記憶體的負擔。

// Car function
var Car = function(loc) {
var obj = {loc: loc};
obj.move = function() {
obj.loc++;
};
return obj;
};
Decorator Pattern 關係圖 :每一個 Car 都會自己的 move function / 取自 Udacity

Prototypal Classes 則是將 move function 新增於 Car 的 prototype,這個時候我們不會在每一次新增物件時,都在記憶體中新增一個 move function 的區域,而是每一次 car 物件執行 move function 時,都會於原型鏈中,往找到存在 Car prototype 的 move function。

var Car = function(loc) {
var obj = Object.create(Car.prototype);
obj.loc = loc;
return obj;
};
Car.prototype.move = function() {
this.loc++;
};
Prototypal Classes 類別物件關係圖:執行時都會參考自相同的 move function / 取自 Udacity

Pseudoclassical Pattern

接著讓我們再優化一下 Prototypal Classes 的方法,透過 new 這個內建的 JS 關鍵字,於這個方法中,雖然大致上與 Prototypal Classes 的方法並沒有太多差別,但可以幫我們減少程式碼,並且會提升 JS 效能。

var Car = function() {
// this = object.create(Car.prototype);

this.loc == loc;
  // return this
}
Car.prototype.move = function() {
this.loc++;
};
var car = new Car(1);

Superclass and Subclass

當我們有多種類別時,有些類別會有階層關係,比方說休旅車是車的一種,卡車也是車的一種,雖然有相似的功能,但也有不同的功能。

ben、cal 物件都有 move, loc,但 ben 有自己的 grab,cal 有自己的 call function / 取自 Udacity

這個時候為了避免重複撰寫相似的功能,我們可以透過繼承的方式 reuse 程式碼。

例如:車子、休旅車都有移動的功能,因此我們不需要在 Ven 類別中,重複撰寫此一功能,而是直接從 Car 類別新增。

/* Superclass and subclass */
// 車子類別
var Car = function(loc) {
var obj = {loc: loc};
obj.move = function() {
obj.loc++;
};
return obj;
};
// 休旅車類別
var Van = function(loc) {
var obj = Car(loc); // 繼承於 Car
 obj.grab = function () {};
return obj;
};

Pseudoclassical Subclass

上述的例子,當然也可以改寫成 Pseudoclassical 的形式。

The call() method calls a function with a given this value and arguments provided individually.
// Car pseudoclassical pattern
var Car = function() {
this.loc == loc;
}
Car.prototype.move = function() {
this.loc++;
};

var Van = function(loc) {
// Using call to chain constructors for an object
// 執行 car constructor 於 this object 上
Car.call(this, loc);
};
// 新增 prototype,此時 Van constructor 會是 Car constructor
Van.prototype = Object.create(Car.prototype);
// 重設 constructor
Van.prototype.constructor = Van;

所有範例程式碼:

本文內容主要根據於 Udacity Object-Oriented JavaScript 線上課程。

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.