從ES6代碼編譯看原型鏈繼承

ES6代碼

class Point {
  x: number;
  y: number;
  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
  }
}

class Point3D extends Point {
  z: number;
  constructor(x:number, y:number, z: number) {
    super(x,y)
    this.z = z;
  }
}

編譯

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) {//參數d是derive(派生)的簡寫,參數b是base的簡寫
        extendStatics(d, b);//繼承靜態成員
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Point = /** @class */ (function () {
    function Point(x, y) {
        this.x = x;
        this.y = y;
    }
    return Point;
}());
var Point3D = /** @class */ (function (_super) {
    __extends(Point3D, _super);
    function Point3D(x, y, z) {
        // _super.call()用於繼承基類的屬性成員
        var _this = _super.call(this, x, y) || this;
        _this.z = z;
        return _this;
    }
    return Point3D;
}(Point));

分析

結合《JavaScript高級程序設計》6.3節繼承中所說,在子類構造函數的內部調用基類構造函數,即_super.call(this, x, y)。這樣在創建子類Point3D實例的時候就會執行基類構造函數的代碼,獲取基類屬性。

__extends函數中主要做了兩件事:

  • 將基類的靜態成員賦值到子類。即extendStatics函數實現的功能。
  • 設置子類函數的原型

針對第二點,簡化代碼如下

function __() { this.constructor = d; }
__.prototype = b.prototype
d.prototype = new __();

如上代碼的最終目的就是d.prototype.__proto__ = b.prototype

通過第3行代碼可以看出d.prototype = {__proto__: __.prototype }
結合第2行代碼,可知d.prototype = {__proto__ : b.prototype}
因此可以獲知最終結果d.prototype.__proto__ = b.prototype
第一行代碼作用是需要保留原始d.prototype.constructor
終極結果就是d.prototype = {__proto__: b.prototype, constructor: d}

小結:這裏的function __(){}作爲中轉函數,將原型鏈傳遞下去。使用結合繼承的方式繼承了普通屬性,靜態屬性和函數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章