身為一個物件導向的程式開發人員,應該不會不知道繼承 (inheritance) 是什麼吧,它可以讓子類別擁有父類別的完整功能,並透過 private/protected/internal 等修飾子 (modifier) 做封裝的保護,子類別也可以存取父類別的資源,子類別也可以選擇允許或不允許給其他物件繼承等等,若是想要在不修改原本物件的情況下擴充原有功能,繼承是一個好方法。
身為一個物件導向的程式開發人員,應該不會不知道繼承 (inheritance) 是什麼吧,它可以讓子類別擁有父類別的完整功能,並透過 private/protected/internal 等修飾子 (modifier) 做封裝的保護,子類別也可以存取父類別的資源,子類別也可以選擇允許或不允許給其他物件繼承等等,若是想要在不修改原本物件的情況下擴充原有功能,繼承是一個好方法。
例如,現在我手上有一個 MathBase 物件 (Mathbase.js),它的物件宣告是這樣的:
1: function MathBase(a, b) {
   2:   
	3: var _a = a;
4: var _b = b;
   5:   
	6: this.a = _a;
7: this.b = _b;
   8:   
	9: this.add = function () { return this.a + this.b; };
10: this.minus = function () { return this.a - this.b; };
  11:   
	
  12:  }
其呼叫方式為:
1: function displayAdd() {
   2:   
	3: var math = new MathBase(1, 2);
4: document.write("1 + 2 = " + math.add());
5: document.write("<br />");
   6:   
	
   7:  }
	
   8:   
	
   9:   
	10: function displayMinus() {
  11:   
	12: var math = new MathBase(1, 2);
13: document.write("1 - 2 = " + math.minus());
14: document.write("<br />");
  15:   
	
  16:  }
執行結果為:
今天,我想要在不改變 Math.js 的情況下擴充它的功能,這時除了用 CP 大法 (copy/paste) 以外,我們還可以多用一樣東西:繼承。只是在 JavaScript 中,繼承的作法和以往的方式完全不同。原有的 MathBase 只有加和減,現在要加上乘和除,我們新增一個 MathV1,宣告如下:
1: MathV1.prototype = new MathBase();
   2:   
	3: function MathV1(a, b) {
   4:   
	
   5:      MathV1.prototype.a = a;
	
   6:      MathV1.prototype.b = b;
	
   7:   
	8: console.log(this);
   9:   
	10: this.multiply = function () {
11: return MathV1.prototype.a * MathV1.prototype.b;
  12:      };
	
  13:   
	14: this.divide = function () {
15: return MathV1.prototype.a / MathV1.prototype.b;
  16:      };
	
  17:   
	
  18:  }
由於 MathV1 要繼承 MathBase 的功能,在 JavaScript 中,我們可以使用 [Object].prototype 屬性來做這件事,它的意思是這個物件的原型是什麼,所以在第一行中,先定義出 MathV1 的原型是來自 MathBase,讓它們有父子關係,這時 Math.prototype 會是 MathBase 的執行個體 (若沒有明確設定,預設值會是物件本身),那麼我們就可以透過 MathV1.prototype 來操作父類別中的物件,包括修改其屬性,或是呼叫方法等等都可以。由於要共用在 MathBase 中宣告的屬性,所以我們在函數中使用的是 MathV1.prototype 來存取宣告在父類別的 a 和 b 屬性。
這時,我們將原本的呼叫程式由 MathBase 改成 MathV1,如下:
   1:   
	2: function displayAdd() {
   3:   
	4: var math = new MathV1(1, 2);
5: document.write("1 + 2 = " + math.add());
6: document.write("<br />");
   7:   
	
   8:  }
	
   9:   
	
  10:   
	11: function displayMinus() {
  12:   
	13: var math = new MathV1(1, 2);
14: document.write("1 - 2 = " + math.minus());
15: document.write("<br />");
  16:   
	
  17:  }
	
  18:   
	19: function displayMultiply() {
  20:   
	21: var math = new MathV1(1, 2);
22: document.write("1 * 2 = " + math.multiply());
23: document.write("<br />");
  24:   
	
  25:  }
	
  26:   
	
  27:   
	28: function displayDivide() {
  29:   
	30: var math = new MathV1(1, 2);
31: document.write("1 / 2 = " + math.divide());
32: document.write("<br />");
  33:   
	
  34:  } 
	
  35:      
	
  36:      
然後在瀏覽器中使用:
你會發現結果一和結果二都可以正常運作,而且變數是共用的。
Object.prototype 還有幾個不同的用法,像是:
	1. 呼叫物件內指定的方法和屬性,但僅能針對公開屬性和方法呼叫,對於私有成員不行。
	2. 更改建構式內容 (Object.prototype.constructor)。
	3. 擴充現有物件,在不使用本文手法之下,這部份可參考:http://www.javascriptkit.com/javatutors/oopjs2.shtml。
經過以上討論,你會發現 JavaScript 的繼承不像是 C# 或 Java 這樣的,由物件本體 (object context) 去繼承,而是透過函數的方式產生的效果,也就是使用 prototype 屬性取代 base (JavaScript 中沒有 base 屬性),同時 prototype 又允許 JavaScript 自由擴充物件,我們後面的幾個特殊功能會利用到這個特性。
Reference:
http://www2.stat.unibo.it/palareti/studenti/linguaggi/jsobj/index.htm
http://webreflection.blogspot.com/2009/06/wait-moment-javascript-does-support.html