TypeScript中Class继承的JS实现

2019-11-10 admin

新建 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实例。

[转载]原文链接:https://segmentfault.com/a/1190000020959487

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-78937.html

文章标题:TypeScript中Class继承的JS实现

相关文章
vue 数组遍历方法forEach和map的原理解析和实际应用
一、前言 forEach和map是数组的两个方法,作用都是遍历数组。在vue项目的处理数据中经常会用到,这里介绍一下两者的区别和具体用法示例。 二、代码 1. 相同点 都是数组的方法 都用来遍历数组 两个函数都有4个参数:匿名函数中可传3...
2018-11-15
一些前端学习中好的书籍,整理
一、Javascript方面的书籍: 1 JavaScript权威指南(第6版):号称javascript圣经,前端必备;前端程序员学习核心JavaScript语言和由Web浏览器定义的JavaScript API的指南和综合参考手册; 2...
2015-11-12
为什么要选择Nodejs?Nodejs有什么好处?
什么?JavaScript还能用作服务器编程! Caleb Madrigal是来自美国密尔沃基市的一名软件顾问。四年前,他在听说“将JavaScript用作服务器端语言”这样的说法时,认为那是一个荒唐的想法。有那么多服务器端语言可供选择,为...
2015-11-12
js性能优化 如何更快速加载你的JavaScript页面
确保代码尽量简洁 不要什么都依赖JavaScript。不要编写重复性的脚本。要把JavaScript当作糖果工具,只是起到美化作用。别给你的网站添加大量的JavaScript代码。只有必要的时候用一下。只有确实能改善用户体验的时候用一下。 ...
2015-11-12
10个强大的纯CSS3动画案例分享
我们的网页外观主要由CSS控制,编写CSS代码可以任意改变我们的网页布局以及网页内容的样式。CSS3的出现,更是可以让网页增添了不少动画元素,让我们的网页变得更加生动有趣,并且更易于交互。本文分享了10个非常炫酷的CSS3动画案例,希望大家...
2015-11-16
请前往任务中心完善资料即可激活会员
登录后,点击右上角的用户名,在下拉菜单中可以进去“我的任务” 注册自动激活,本站没有VIP!没有充值!没有推广任务等等 回复即可下载 ...
2015-11-18
Android中Okhttp3实现上传多张图片同时传递参数
之前上传图片都是直接将图片转化为io流传给服务器,没有用框架传图片。 最近做项目,打算换个方法上传图片。 Android发展到现在,Okhttp显得越来越重要,所以,这次我选择用Okhttp上传图片。 Okhttp目前已经更新到Okhttp...
2017-03-17
v-charts | 饿了么团队开源的基于 Vue 和 ECharts 的图表工具
在使用echarts生成图表时,经常需要做繁琐的数据类型转化、修改复杂的配置项,v-charts的出现正是为了解决这个 痛点。基于Vue2.0和echarts封装的v-charts图表组件,只需要统一提供一种对前后端都友好的数据格式 设置简...
2018-05-24
Node.js 2014这一年发生了什么
Node.js 的 2014 年充满了不幸和争议. 这一年 Noder 们经历了太多的伤心事, 经历了漫长的等待, 经历了沉重的分裂之痛. 也许 Noder 们不想回忆14年 Node.js land 发生的事情, 但正因为痛才更有铭记的价...
2015-11-12
JavaScript实现PC手机端和嵌入式滑动拼图验证码三种效果
PC和手机端网站滑动拼图验证码效果源码,同时包涵了弹出式Demo,使用ajax形式提交二次验证码所需的验证结果值,嵌入式Demo,使用表单形式提交二次验证所需的验证结果值,移动端手动实现弹出式Demo三种效果 首先要确认前端使用页面,比如...
2017-03-17
回到顶部