TypeScript中的继承内置类型

本文介绍了如何将TypeScript中的类转换为ES5代码,重点关注`MsgError`类的继承和原型设置,以及为何在ES5中需要显式设置`Object.setPrototypeOf`以保持原型链的正确性。
摘要由CSDN通过智能技术生成

最近在学习TypeScript,也不知道看的是不是官方文档。本文会根据文档给出的例子和说明展开。

文档中的示例如下:

class MsgError extends Error {
  constructor(m: string) {
    super(m);

    // Set the prototype explicitly.
    Object.setPrototypeOf(this, MsgError.prototype);
  }

  sayHello() {
    return "hello " + this.message;
  }
}

现在我们尝试把这段代码编译成es5的js代码。

"use strict";
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");
        // 继承静态属性和方法,如果Object.setPrototypeOf和__proto__都不存在,会把基类上的属性复制到派生类上
        extendStatics(d, b);
        /*
        将构造函数原型的constructor属性设置为构造函数本身。通过检查对象实例的constructor属性,
        我们可以确定对象实例是由哪个构造函数创建的。比如instanceof运算符,它会沿着对象实例的原型
        链向上查找,判断对象实例的原型链上是否存在指定构造函数的原型。
        本例中: MsgError.prototype.constructor === MsgError
        */
        function __() { this.constructor = d; }
        /*
        如果 b 是 null,将派生类的原型对象设置为一个空对象,且原型指向null
        否则,d.prototype.__proto__ = b.prototype
        ps: (__.prototype = b.prototype, new __())使用了逗号运算符,它可以在一行代码中执行多
        个表达式,并返回最后一个表达式的值。
        */
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var MsgError = /** @class */ (function (_super) {
    __extends(MsgError, _super);
    function MsgError(m) {
        var _this = _super.call(this, m) || this;
        // Set the prototype explicitly.
        Object.setPrototypeOf(_this, MsgError.prototype);
        return _this;
    }
    MsgError.prototype.sayHello = function () {
        return "hello " + this.message;
    };
    return MsgError;
}(Error));

接下来我们按文档说明逐行解析:

翻译:返回对象的构造函数隐式地将this的值替换为super(...)的任何调用者。生成的构造函数代码必须捕获super(...)的任何潜在返回值并将其替换为this。

解释:这在示例中体现为"var _this = _super.call(this, m) || this;"。

翻译:因此,Error、Array和其他JavaScript的原生构造函数的子类可能不再按预期工作。这是因为Error、Array等的构造函数使用es6的new.target来调整原型链。但是,在es5中调用构造函数时,没有办法确保new.target的值。默认情况下,其他的下级编译器具有相同的限制。

如果不设置"Object.setPrototypeOf(this, MsgError.prototype);",你可能会发现:

  1. 这些子类的构造函数返回的对象的方法可能是undefined,所以调用sayHello会报错。
  2. instanceof会在子类的实例与子类之间断开。(new MsgError()) instanceof MsgError将会返回false。

解释:在es5中,原生的构造函数的原型属性是不可配置的。以new关键字调用Error的构造函数时,虽然更改了this的指向,但内部的new.target始终等于Error,因此返回的实例对象_this的__proto__属性指向的是Error的原型。

翻译:您可以在任何super(...)调用后立即手动调整原型。MsgError的任何子类也必须手动设置原型。对于不支持Object.setPrototypeOf的运行时,你可以使用__proto__替代。

解释:在示例中通过"Object.setPrototypeOf(_this, MsgError.prototype);"手动调整原型。对于所有直接或间接继承于Error的类都是不可配置的。如果MsgError的子类创建了实例且没有手动调整原型,它的__proto__属性指向的是MsgError的原型。

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值