TypeScript中Class继承的JS实现

新建 index.ts 文件,实现 SubType 继承 SuperType。

//index.ts
class SuperType {
    name: String;
    constructor(name:String){
        this.name = name;
    }
    getName():String{
        return this.name
    }
}
class SubType extends SuperType {
    constructor(name:String){
        super(name);
    }
}

将 index.ts 编译为 index.js

//index.js
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 __());
    };
})();
var SuperType = (function () {
    function SuperType(name) {
        this.name = name;
    }
    SuperType.prototype.getName = function () {
        return this.name;
    };
    return SuperType;
}());
var SubType = (function (_super) {
    __extends(SubType, _super);
    function SubType(name) {
        return _super.call(this, name) || this;
    }
    return SubType;
}(SuperType));

我们首先分析编译后的SuperType, 可以看出SuperType就是一个自执行函数,执行过程中生成构造函数并将原型方法绑定在构造函数上,最终返回构造函数。

/*创建自执行函数*/
var SuperType = (function () {
    /*构造函数*/
    function SuperType(name) {
        this.name = name;
    }
    /*绑定原型方法*/
    SuperType.prototype.getName = function () {
        return this.name;
    };
    /*返回构造函数*/
    return SuperType;
}());

然后SubType与SuperType有两点不同,多了两个地方。

/*自执行函数,参数_super值为SuperType*/
var SubType = (function (_super) {
    /*继承函数*/
    __extends(SubType, _super);
    function SubType(name) {
        /*将父类的实例属性和方法绑定到子类的实例*/
        return _super.call(this, name) || this;
    }
    return SubType;
}(SuperType));

先看 _super.call(this, name);,这里实际是执行SuperType构造函数并将构造函数的this指向当前创建的SubType实例。 要明白这一点首先要知道在new一个实例的时候发生了什么。

/*当我们new一个实例时*/
var o = new SubType();
/*我们可以理解为*/
/*
1.创建一个空的对象
2.将对象的__proto__指向类的prototype
3.调用构造函数并将构造函数的this指向对象,以此将构造函数上的属性绑定在对象上。
*/
var o = {};
o.__proto__ = SubType.prototype;
SubType().call(o,name)

因为在执行 SubType().call(o,name)时 子类构造函数 SubType() 中的 this 已经指向实例 o ,所以当调用 子类中的 _super.call(this, name)其 this 即指向实例 o,因此便可将父类构造函数 SuperType()中的实例属性和方法继承到了在子类的实例上。

接下来来看 SubType() 下的 __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 __());
    };
})();

首先判断__extends()方法是否已经被声明。

/*若在当前环境下已经被声明,则返回this.__extends,否则返回(function(){})();  */
var __extends = (this && this.__extends) || (function () {
...
})();

然后看返回的自执行函数 (function(){})()

var __extends = (function () {
    var extendStatics = function (d, b){...}
    //返回一个匿名函数
    return function (d, b) {
        //调用闭包中extendStatics()方法
        extendStatics(d, b);
        //定义一个构造函数__()
        function __() { this.constructor = d; }
        //判断b是否为空,是的话则 d.prototype = Object.create(b)
        //否则 d.prototype = (__.prototype = b.prototype, new __())
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();

重点看d.prototype = (__.prototype = b.prototype, new __());

d.prototype = (__.prototype = b.prototype, new __())
//其步骤为
//1.将__.prototype指向 b即父类的 prototype
  __.prototype = b.prototype;
//2.实例化一个__()
  let _o = new __();
//3.将 d即子类的的 prototype 指向 new __()
  d.prototype = _o;

//相当于做了
d.prototype.__proto__ = b.prototype;
d.prototype.constructor = d;

以此实现了子类对父类原型方法的继承。

下面来看闭包中extendStatics = function (d, b){...}的定义

var extendStatics = function (d, b) {
    //当浏览器支持Object.setPrototypeOf时返回
    extendStatics = Object.setPrototypeOf ||
        //当浏览器支持__proto__时返回
        ({ __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);

这一段代码做了兼容性处理,实际在做的就是 d.__proto__ = b即实现了子类对父类静态方法的继承。

总结

typescript 的继承,实际上相对用javascript实现了

function SubType(){
    SuperType().call(this);
}
SubType.prototype.constructor = SubType;
SubType.prototype.__proto__ = SuperType.prototype;
SubType.__proto__ = SuperType;

了解了typescript的继承原理后,我们在使用typescript继承时就要注意一些问题,比如深浅拷贝。

PS

在看代码时碰到的小点,在此记录。 { __proto__: [] } instanceof Array是如何工作的? 个人理解为当浏览器不支持__proto__时,{ __proto__: [] }相当于为对象{}定义了一个值为[]__proto__属性;但当浏览器支持__proto__时,相当于将{}的原型指向了一个Array实例。

原文链接:segmentfault.com

上一篇:typescript中class继承的js实现
下一篇:wait-for-redis

相关推荐

  • 🙋Hanjst汉吉斯特改进+enSafeExpression安全表达式等

    Hanjst汉吉斯特模版语言及模版引擎,近期持续改进升级。 这次改进主要是增加了对安全输出表达式兼容,由于涉及到对软件开发过程中的效率和软件运行效率的平衡和取舍,所以多写了几句,以描述这个权衡利弊对...

    13 天前
  • 🙋Hanjst汉吉斯特升级:+showImageAsync及性能改进等

    自2019年元旦🙋Hanjst汉吉斯特 模板语言及其编译引擎发布,已经过去一年多了。 这期间随着 🙋Hanjst汉吉斯特 的推广应用,我们也陆续发布了如下一些更新内容: 🛠️Hanjst/汉吉...

    2 个月前
  • 😉我用 Nuxt.js 仿了个掘金

    前言 首先肯定是要夸夸掘金啦,最开始从 CSDN 到 博客园 再到 掘金,个人感觉掘金的技术氛围非常的nice,真是个宝藏社区👏。技术文章大多以前端为主,对前端开发者非常友好,质量也是歪瑞古的。

    24 天前
  • 😀一个原生js弹幕库

    danmujs 😀一个原生js弹幕库,基于 CSS3 Animation 地址、核心代码 本项目基于 rcbullets,项目约70%的代码基于rcbullets,首先要感谢这个项目的作者,如...

    4 个月前
  • 🕵️‍♀️由原型到JS中的“模拟类”

    讲述了有关 JavaScript 中原型相关知识,又引出了 JavaScript 中的“类“究竟是什么?,以及一系列相关问题。 一、前置知识 1、JavaScript 的面向对象(OOP) ​ 面向...

    2 个月前
  • 🔥《吊打面试官》系列 Node.js 必知必会必问!

    (/public/upload/f204a3b224d986128f1b4d9b8d06cd17) 前言 codeing 应当是一生的事业,而不仅仅是 30 岁的青春🍚 本文已收录 Git...

    3 个月前
  • 💖CSS + JS 送学妹满屏幕小爱心

    故事开始 午饭时间,暗恋已久的学妹拉着我的衣袖:“学长学长,你能不能让这些爱心变成五颜六色的吗~”。 我在旁边笑开了花~~~ image.png(/public/upload/04aaa24e...

    1 个月前
  • (vuejs学习)2、使用ElementUI(*)

    1.element安装 开发环境是win10,一到node官网下载node的.msi包(https://npm.taobao.org/mirrors/node/v10.16.0/nodev10.16....

    10 个月前
  • (vuejs学习)1、Vue初上手(*)

    参考《官方(https://cli.vuejs.org/zh/guide/installation.html)》官方: Node 版本要求: Vue CLI 需要 Node.js 8.9 或更高...

    10 个月前
  • 黄金搭档 -- JS 装饰器(Decorator)与Node.js路由

    很多面对象语言中都有装饰器(Decorator)函数的概念,Javascript语言的ES7标准中也提及了Decorator,个人认为装饰器是和一样让人兴奋的的变化。

    1 年前

官方社区

扫码加入 JavaScript 社区