物件導向有三大基本特徵: 繼承, 封裝, 多型.
繼承就是子類別繼承了父類別. 例如: 學生(子類別)繼承了Person人(父類別)原有的屬性(property)以及方法(function), 也新增了自己特有的屬性(property)或方法(function).
在Javascript 中, 我們先定義一個Student Class
function Student() {
this.name = "neil";
}
這個Student 物件定義沒有greeter 方法, 這時候如果我們想將Student Class 繼承Person Class ,但Javascript 並沒有其他物件導向語言那般定義的方法.
所以需要再用下面程式碼來模擬繼承
Student.prototype = Object.create(Person.prototype);
它透過用Object.create 方法複製Person prototype 定義並且指定給Student.prototype .
完整的Javascript 程式碼示範如下
function Person() {
this.name = "flash";
this.age = 50;
return this;
}
Person.prototype.greeter = function () {
return "Hello " + this.name;
};
function Student() {
this.name = "flash";
}
Student.prototype = Object.create(Person.prototype);
var p = new Student();
console.log(p.greeter());
你可以將上述示範程式碼內容複製到 jsbin 進行實作測試實驗結果.
如無意外, 你在 jsbin 控制台可以看到輸出結果
Hello flash
這時候你再測試下面的程式碼
console.log(p.age);
你會看到結果是
undefined
為什麼? 還記得上篇中有說過
在Javascript 中最正統標準(也最清楚)的定義物件的作法就是用 function 加上 prototype 去定義物件(Class)
所以 age 屬性就得用 prototype 方式去定義.
Person.prototype.age = 50;
接下來我們來看看, 在Demo.ts 用Typescript 定義上述相同的程式碼
class Person {
name: string = "flash";
age: number = 50;
greeter() : string {
return "Hello " + this.name;
}
}
class Student extends Person {
name: string = "neil;
}
在Typescript 世界想要做到繼承很簡單, 只需要一個關鍵字 extends .
我們觀察一下Typescript 所產生的 .js 程式碼, 你會發現它先自動產生 __extends() 方法,
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
在Student 定義的地方, 再用 __extends() 方法來複製繼承 Person Class 的定義
var Student = /** @class */ (function (_super) {
__extends(Student, _super);
function Student() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.name = "neil";
return _this;
}
return Student;
}(Person));
這時候你會想, 天啊! 為什麼Javascript 繼承方法要弄得這麼複雜? 實際上在Javascript 世界裡有prototype 還有 __proto__ , constructor.
__proto__ 最先被Firefox 使用, 後來在 ES6 被列為Javascript 的標準內建屬性的
而且Javascript 中的承繼作法有很多方法, 有些人是透過 Object.create(), 有一些人是 Object.assign(), 最流行的方法是透過constructor 建立實例(instance), 自動化設定新建物件(object) 的 prototype 屬性, 並把它存放在 ConstructorFunction.prototype 裡面.
光是搞清楚這些東西就已經頭大了, 簡單一點就好, 來! 我們用Typescript 打上 extends 達到繼承, 這件事情就可以結束了.