Javascript - 物件導向設計(EcmaScript 6之前)

Javascript 是 Web 上最常使用的程式語言,現今大部分的瀏覽器內部都有 Javascript Engine,可以執行頁面的 Javascript,透過 Javascript 與 AJAX 可以實作出富有高UI/UX質量的SPA(Single Page Application),這也是目前Web的趨勢。但是由於Javascript的語法與 Java, .Net, C/C++... 等物件導向程式語言大相逕庭,導致習慣於 OO (Object-Oriented) 開發的程式開發人員會很難上手,但其實Javascript是有辦法實作類似 OO 的方式,本篇限量就要來說明如何使用 Javascript 的 OO Design 方式。


P.S.:後來發現從ECMAScript6開始,Javascript就有 class 相關的操作與識別字,真是太棒了,但是對於那該死的 IE 只有在 IE11 才有部分支援 class 識別字,所以如果不想管相容性的情況當然會比較推薦使用 ECMAScript6的功能囉,不然就是使用 Typescript 來編譯(本篇介紹的方式為未使用 ECMAScript6的方式)。

Javascript的基本資料型態由 Number, String, Array, Object 組成,其中 Object 是當中最深奧, 最容易搞混也是變化最多的一種類型,因為 Object 在 Javascript 中是模糊抽象的,它可以動態擴增屬性,屬性的資料型態也是未定義的,所以在使用 Object 的時候千萬要小心,必須要檢查屬性值是否為 undefined 或 null。

基本上,我們在 Javascript 上進行 OO Design 都是用 Object 來實作,接下來要來說明如何透過 Object 進行 OO Design:


Namespace


Namespace 在 OO 的概念中是將程式分成區塊,用來細分區別 Class 名稱,就像是C#的 namespace, Java 的 package。在各區塊中可以定義相同的 Class 名稱,只要 Class 的整個絕對路徑有差異就算合法的。舉個例子來說:船和汽車都有引擎,但是兩者的引擎構造不一樣,所以當我們使用語言表示時會說"船"的"引擎""汽車"的"引擎",這樣聽的人就知道我們在說什麼。換作程式語言來表示的話會變成 Boat.Engin Car.Engine,這樣程式執行就可以識別是哪個 Class。

在 Javascript 中沒有 namespace 或 package 這種識別字,但是我們可以用 Object 的階層特性來表示 Namespace,例如:
var Japan = {
    Car: {
        Engine: {...},
        Wheel: {...},
        StreeringWheel: {...}
    },
    Boat: {
        Engine: {...},
        Wheel: {...}
    }
};

var Taiwan = {
    Car: {
        Engine: {...},
        Wheel: {...}
    }
};

或者可以用另一種寫法表示:
if(typeof Japan === "undefined") {
    var Japan = {};
}

if(typeof Taiwan === "undefined") {
    var Taiwan = {};
}

Japan.Car = {
    Engine: {...},
    Wheel: {...},
    SteeringWheel: {...}
};

Japan.Boat = {
    Engine: {...},
    SteeringWheel: {...}
};

Taiwan.Car = {
    Engine: {...},
    Wheel: {...},
    SteeringWheel: {...}
};



Class


Class 是將一段程式模組的敘述, 執行動作, 描述, 狀態, 特徵...等特性封裝在一起成為一個類別,例如:狗和汽車是完全不同的東西,狗會跑會叫, 有耳朵, 尾巴...等;汽車要加油, 發動, 有引擎, 輪子...等,針對各類型的描述我們將他包裝成 Dog 和 Car 的 Class。然而 Class 可以有許多執行個體,各執行個體基本上不會互相影響,除非有 Static 成員。

Javascript 中也沒有 Class 這種識別字,我們以 Function Object 來實現 Class 的概念。Function Object 其實就是 Javascript 的 Function,不管是自定義的還是原生的,本質都是一個 Object,我們要利用的是 Function Object 的 prototype 屬性,當我們定義了一個 Function,該 Function 就會有一個 prototype 屬性,呼叫它就可以得到這個 Function 自身,接著我們只要透過 [Function名稱].prototype.[成員名稱] 就在這個 Function 裡定義了一個成員,定義的屬性可以是數字, 物件, Function。下面是一個實現 Class 的範例:
var Pig = function(name) {
    this.name_ = name;
};

Pig.prototype.legCount = 4;

Pig.prototype.shout = function() {
    alert('Pig! Pig! ' + this.name_);
};

限量定義了一個 Pig 的 Class,legCount為屬性值;shout 為執行 alert 的方法。這裡要注意的是在定義成員的時候,裡面的 this 代表的是此 Function 的自身,也就是Function.prototype,如果裡面還又在定義其他 Inner Function 就要注意 Javascript Closure 的問題。

Class 定義完後就要來產生實體執行,如下:
var pig = new Pig('426');
pig.legCount; // result: 4
pig.shout(); // result: Pig! Pig! 426

慶幸的是還好還有 new 的識別字,這個 new 和 C#, Java 一樣是用來在記憶體中產生新實體的識別字,產生出的實體會是各自獨立。 


學會了簡單的 Namespace 與 Class 定義後,在撰寫 Javascript 就可以更加漂亮更加簡單也更好維護,當然後面還有其他 OO 的進階概念也是可以在 Javascript 中實現出來。


站內相關文章:
Javascript - 繼承(EcmaScript 6之前)



留言