「繼承」是物件導向程式設計中一個重要也是核心的觀念,動詞原文為 inherit 。雖然 inherit 在英文的意思泛指從什麼得到什麼,用作中文「繼承」說得通,也能用作「遺傳」。然而中文的「繼承」隱含某物不再,另物將起的意思,譬如「我繼承某某的精神」,雖然某某不見得已死,未來將要付出努力的卻是我而非某某。因而這裡的意思中文用「遺傳」比較恰當,子代會從親代遺傳某些生物特性,子代與親代也會並存一段時間,這就沒有某物不再的意含了。然而這裡我們仍沿用程式設計常用的「繼承」一詞,但仍提出意見以免讀者混淆。
舉例如下
function run() { var c = document.getElementById("content"); var n1 = document.createElement("p"); var n2 = document.createElement("p"); var n3 = document.createElement("p"); var n4 = document.createElement("p"); var n5 = document.createElement("p"); var n6 = document.createElement("p"); var t1 = new Elephant(); var t2 = new Elephant(); var t3 = new Elephant(); var t4 = t1.speak(); var t5 = t2.speak(); var t6 = t3.speak(); n1.appendChild(document.createTextNode(t1)); c.appendChild(n1); n2.appendChild(document.createTextNode(t2)); c.appendChild(n2); n3.appendChild(document.createTextNode(t3)); c.appendChild(n3); n4.appendChild(document.createTextNode(t4)); c.appendChild(n4); n5.appendChild(document.createTextNode(t5)); c.appendChild(n5); n6.appendChild(document.createTextNode(t6)); c.appendChild(n6); } function Animal() { this.age = 0; this.weight = 0; } Animal.prototype.speak = function() { return "哈囉,我已經" + this.age + "歲,有" + this.weight + "公斤重" } function Elephant() { this.wname = "nobody"; } Elephant.prototype = new Animal; /* 《程式語言教學誌》的範例程式 http://pydoing.blogspot.com/ 檔名:herit01.js 功能:示範 JavaScript 程式 作者:張凱慶 時間:西元 2010 年 11 月 */
利用以下的 HTML 文件開啟
<html> <head> <title>JavaScript Demo</title> <script src="herit01.js" type="text/javascript"></script> </head> <body> <input id="b" type="button" value="RUN" onclick="run();"> <div id="content"></div> </body> </html> <!-- 《程式語言教學誌》的範例程式 http://pydoing.blogspot.com/ 檔名:herit01.html 功能:示範 JavaScript 程式 作者:張凱慶 時間:西元 2010 年 11 月 -->
執行結果如下
我們在第 31 行定義了 Animal 物件的建構子函數 (constructor function) ,並且定義了一個 speak() 方法
function Animal() { this.age = 0; this.weight = 0; } Animal.prototype.speak = function() { return "哈囉,我已經" + this.age + "歲,有" + this.weight + "公斤重" }
然後在第 39 行定義另一個 Elephant 物件
function Elephant() { this.wname = "nobody"; } Elephant.prototype = new Animal;
繼承定義在第 42 行
Elephant.prototype = new Animal;
我們將 Elephant 物件的 prototype 屬性指派一個新的 Animal ,因此 Elephant 物件得以繼承 Animal 的屬性及方法,所以 run() 函數 (function) 中所新建的三個 Elephant 物件,可以呼叫執行 speak() 方法 。
然而上面的提供的繼承寫法並不具有彈性,屬性直接提供預設值。以下的寫法在建構子函數中可以提供參數 (parameter)
function run() { var c = document.getElementById("content"); var n1 = document.createElement("p"); var n2 = document.createElement("p"); var n3 = document.createElement("p"); var n4 = document.createElement("p"); var n5 = document.createElement("p"); var n6 = document.createElement("p"); var t1 = new Elephant(98, 3000, "林旺"); var t2 = new Elephant(52, 2456, "伊芙"); var t3 = new Elephant(12, 1300, "小黑"); var t4 = t1.speak(); var t5 = t2.speak(); var t6 = t3.speak(); n1.appendChild(document.createTextNode(t1)); c.appendChild(n1); n2.appendChild(document.createTextNode(t2)); c.appendChild(n2); n3.appendChild(document.createTextNode(t3)); c.appendChild(n3); n4.appendChild(document.createTextNode(t4)); c.appendChild(n4); n5.appendChild(document.createTextNode(t5)); c.appendChild(n5); n6.appendChild(document.createTextNode(t6)); c.appendChild(n6); } function Animal(age, weight) { this.age = age || 0; this.weight = weight || 0; } Animal.prototype.speak = function() { return "哈囉,我已經" + this.age + "歲,有" + this.weight + "公斤重" } function Elephant(age, weight, wname) { this.base = Animal; this.base(age, weight); this.wname = wname || "nobody"; } Elephant.prototype.speak = function() { return "我的名字是" + this.wname + "已經" + this.age + "歲" } /* 《程式語言教學誌》的範例程式 http://pydoing.blogspot.com/ 檔名:herit02.js 功能:示範 JavaScript 程式 作者:張凱慶 時間:西元 2010 年 11 月 */
利用以下的 HTML 文件開啟
<html> <head> <title>JavaScript Demo</title> <script src="herit02.js" type="text/javascript"></script> </head> <body> <input id="b" type="button" value="RUN" onclick="run();"> <div id="content"></div> </body> </html> <!-- 《程式語言教學誌》的範例程式 http://pydoing.blogspot.com/ 檔名:herit02.html 功能:示範 JavaScript 程式 作者:張凱慶 時間:西元 2010 年 11 月 -->
執行結果如下
我們提供兩個參數給 Animal() ,其中
this.age = age || 0; this.weight = weight || 0;
參數會被指派給屬性,這裡連用邏輯或運算子 (operator) ,表示若沒有提供參數,便將 || 之後的預設值指派給屬性。
Elephant 的建構子函數定義在第 39 行
function Elephant(age, weight, wname) { this.base = Animal; this.base(age, weight); this.wname = wname || "nobody"; } Elephant.prototype.speak = function() { return "我的名字是" + this.wname + "已經" + this.age + "歲" }
Elephant 多一個 base 屬性,其為 Animal ,然後利用 base 呼叫 Animal 的建構子函數,使 Elephant 繼承 Animal 的屬性,最後我們利用物件的 prototype 屬性動態增加 speak() 方法。
注意這裡的 prototype 是屬於動態增加的方式,如果是用 prototype 來繼承,利用 prototype 定義的方法都會被繼承下來。上例中我們利用的是 base 來繼承屬性,因此 Animal 用 prototype 定義的 speak() 並不會被繼承。
中英文術語對照 | |
---|---|
原型基礎 | prototype-based |
物件導向程式設計 | object-oriented programming, OOP |
物件 | object |
繼承 | inheritance |
屬性 | attribute |
方法 | method |
建構子函數 | constructor function |
函數 | function |
參數 | parameter |
運算子 | operator |
沒有留言:
張貼留言