typescript 中 class 继承的 ES5 实现

73 阅读2分钟

基础概念

高级程序设计书中有描述 JS 实现继承的方案有五种

  1. 原型链继承
  2. 盗用构造函数继承
  3. 组合继承
  4. 寄生式继承
  5. 寄生式组合继承

组合继承和寄生式组合继承使用的继承场景不一致

组合继承适用于构造函数来创建属性、方法

寄生式组合继承适用于在使用既有对象进行继承、不需要构造函数创建属性、方法的场景

typescript 修改构建产物为 ES5 版本后、class 继承的实现就是基于寄生式组合继承

class A {
  name: string
  constructor(name) {
    this.name = name
  }
  colors: string[] = ['red']
}

class B extends A {
  constructor(name: string) {
    super(name)
  }
}

const b = new B('xxxx')

编译产物

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 (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototypenew __());
    };
})();
var A = /** @class */ (function () {
    function A(name) {
        this.colors = ['red'];
        this.name = name;
    }
    return A;
}());
var B = /** @class */ (function (_super) {
    __extends(B, _super);
    function B(name) {
        return _super.call(this, name) || this;
    }
    return B;
}(A));
var b = new B('xxxx');

梳理后

var __extends = (function () {
        // 拷贝目标
        var extendStatics = function (d, b) {
          //   Object.setPrototypeOf ||
          //     ({ __proto__: [] } instanceof Array &&
          //       function (d, b) {
          //         d.__proto__ = b
          //       }) ||
          //     function (d, b) {
          //       for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]
          //     }
          //   return extendStatics(d, b)

          // var xxxx = function () {
          //     xxxx = '123'
          //     console.log(xxxx)
          // }
          // xxxx() // 123

          // 这里是 extendStatics 的兼容实现
          // 支持 Object.setPrototypeOf 语法就使用这个语法
          // extendStatics 是函数内部作用域的变量 var 关键字可以没有只是和变量同名
          var extendStatics

          if (Object.setPrototypeOf) {
            extendStatics = Object.setPrototypeOf
            return extendStatics(d, b)
          }

          // setPrototypeOf 的兼容实现
          var o = {
            __proto__: []
          }

          var a = function (d, b) {
            d.__proto__ = b
          }

          // 支持 __proto__ 方式修改原型链指向就使用 a 函数也就是 setPrototypeOf 的替补实现
          if (o instanceof Array) {
            extendStatics = a
            return extendStatics(d, b)
          }

          // 拷贝对象属性的方法
          function xxx(d, b) {
            for (var p in b) {
              if (Object.prototype.hasOwnProperty.call(b, p)) {
                d[p] = b[p]
              }
            }
          }
          // extendStatics 的兜底实现
          extendStatics = xxx
          return extendStatics(d, b)
        }

        // 返回具体的继承实现函数
        return function (d, b) {
          if (typeof b !== 'function' && b !== null)
            throw new TypeError(
              'Class extends value ' + String(b) + ' is not a constructor or null'
            )
            
          // 拷贝b 到 d
          extendStatics(d, b)
          
          function __() {
            this.constructor = d
          }
       
          //   d.prototype = b === null ? Object.create(b) : ((__.prototype = b.prototype), new __())
          if (b === null) {
            d.prototype = Object.create(b) // d 的原型指向是 null
          } else {
            __.prototype = b.prototype
            // 这里就是寄生式继承的方案了
            d.prototype = new __()
          }
        }
      })()

      var A = /** @class */ (function () {
        function A(name) {
          this.colors = ['red']
          this.name = name
        }
        return A
      })()

      // 寄生式组合继承
      var B = /** @class */ (function (_super) {
        // 寄生式继承
        __extends(B, _super)
        function B(name) {
          // 盗用构造函数继承
          return _super.call(this, name) || this
        }
        return B
      })(A)
      var b = new B('xxxx')
      console.log(b)

最后:书真是个好东西啊