iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 4
3
Software Development

為什麼世界需要Typescript系列 第 4

物件導向的繼承 - 04

物件導向有三大基本特徵: 繼承, 封裝, 多型.

繼承(inherit)

繼承就是子類別繼承了父類別. 例如: 學生(子類別)繼承了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 達到繼承, 這件事情就可以結束了.


上一篇
定義物件 - 03
下一篇
物件導向的封裝繼承 - 05
系列文
為什麼世界需要Typescript30

尚未有邦友留言

立即登入留言