详解Typescript中继承的实现
来源:互联网 发布:泛微java怎么样 编辑:程序博客网 时间:2024/06/03 21:17
学习javascript也有一段时间了,打算从今天开始记录自己的一些理解。
此篇文章主要是记录自己对Typescript在编译成es5的代码时如何实现继承的理解。
首先是测试代码
class Sup { public static staticProp = "静态属性"; public instanceProp = "实例属性"; public foo(): string { return "原型方法"; }}class Sub extends Sup { public constructor() { super(); }}let subObj = new Sub();console.log(Sub.staticProp);console.log(subObj.instanceProp);console.log(subObj.foo());
执行结果如下,可以看到,子类成功继承了父类的静态成员和实例成员,其中父类的foo方法在编译成es5代码后是绑定到Sup构造函数的prototype属性上的。
编译出来es5代码如下
var __extends = (this && this.__extends) || (function () { var 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 function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); };})();var Sup = (function () { function Sup() { this.instanceProp = "实例属性"; } Sup.prototype.foo = function () { return "原型方法"; }; return Sup;}());Sup.staticProp = "静态属性";var Sub = (function (_super) { __extends(Sub, _super); function Sub() { return _super.call(this) || this; } return Sub;}(Sup));var subObj = new Sub();console.log(Sub.staticProp);console.log(subObj.instanceProp);console.log(subObj.foo());
可以看到继承的实现是通过__extends函数和在子类构造函数里以call的方式调用父类构造函数来实现的,接下来来看看这个__extends函数,这个函数与老版本的编译器编译出来的是有所区别的,下面还是以新版本的编译结果作为说明对象。为了方便注释,对这个函数的书写格式进行了一些调整。
// 首先来看下这个(this && this.__extends) || ...的写法// 在js中,布尔运算可以用于任何类型,运算的结果取决于参与运算的变量被转成布尔型后的对应布尔值,// 当然这句话不说布尔运行的结果一定是布尔值,下面举一个例子// 分别对null和{}调用Boolean()转型函数,结果是false和true// var test = null || {}; test为{},var test = {} && null ; test为null// 如果这段代码是在全局作用域的环境下执行的,this为全局对象,浏览器下即为window对象。// 全局作用域下定义的函数是作为全局对象的方法被创建的,// __extends函数在全局作用域中被第一次声明后,this.__extends即指向__extends函数。// 在存在多个写有继承的TS文件的时候,每个对应的js文件都会有这串代码,// 如果__extends已经作为全局变量的方法被定义过了。// 那么就不再为__extends变量重新指定新的函数对象。// 反之如果__extends函数尚未存在,就将||符号右边的值赋值给__extends变量,// (function(){})();的写法被称为IIFE(立即执行函数表达式)。var __extends = (this && this.__extends) || (function () { // 从这个函数的名字就可以看到它是实现静态的属性的继承的 // 静态属性就是直接绑定在构造函数这个函数对象上的属性 var extendStatics = // Object.setPrototypeOf能够接受两个参数,用法如下 // var obj = {},proto = {x:10}; // Object.setPrototypeOf(obj, proto); // console.log(obj.x); // 10 // 上面代码将proto对象设为obj对象的原型,所以从obj对象可以读取proto对象的属性。 // 具体可以参考阮一峰的ECMAScript 6 入门(http://es6.ruanyifeng.com/#docs/object) Object.setPrototypeOf || // 如果浏览器不支持上面的Object.setPrototypeOf方法,则会跑到这里 // {__proto__: []} instanceof Array用来判断浏览器是否支持__proto__属性,不支持则返回最后一项 ({__proto__: []} instanceof Array && function (d, b) { // 效果和上面用Object.setPrototypeOf方法是一样的,这边更粗暴一点 d.__proto__ = b; }) || function (d, b) { // 老版本的编译器对于静态属性的继承是用这一块代码实现的, // 稍后将贴出老版本编译器生成的代码 // 这块代码是将Sup函数对象的实例方法或者属性浅拷贝给Sub函数对象 // (用hasOwnProperty排除了apply等从原型链上继承过来的方法) for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; // 这个是真正的__extends函数本体 // 参数d为Sub,b为Sup return function (d, b) { // 这个最终返回的匿名函数作为闭包能够访问到外层函数作用域的extendStatics函数 // 闭包的定义:有权访问另一个函数作用域中的变量的函数 // 注意,是这个返回的匿名函数被称为闭包 // 之所以采用这样的方式,一旦extendStatics通过第一次的布尔运算被确定下来, // 以后每次调用__extends函数的时候就可以用这个确定下来的extendStatics函数了 extendStatics(d, b); function __() { // 因为下面要用这个构造函数的实例来重写Sub函数的原型对象, // 若不重新将原型对象的constructor属性指向Sub函数, // 则将直接指向Object构造函数,就不能通过constructor确定subObj对象的类型了。 this.constructor = d; } // 当让Sub继承null即"class Sub extends null"的时候, // 会调用这个Object.create函数, // Object.create(null)会返回一个没有任何属性和方法的对象 // 和用new Object()或对象字面量{}创建对象不同, // 后者会从Object原型上继承属性和方法。 // "class Sub extends null"即表明Sub.prototype就是它所在原型链的开端 // 接下来讨论extend后面跟的是个的类的时候 // 将__函数的prototype指向Sup.prototype,然后将__函数的实例作为Sub的prototype // 本质上对Sup.prototype的一个浅拷贝, // 如果直接将Sup.prototype赋给Sub.prototype也可以实现原型继承 // 但后者会导致在Sub.prototype上挂在属性和方法时影响到Sup。 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })();
上面介绍了__extends函数对静态成员和原型上定义的成员的继承的实现。实例属性的继承就比较简单了,只用call的方式调用父类构造函数,此时Sup函数中的this指向新创建的Sub的实例。Sup函数对this添加的成员也成功添加到Sub的实例上了。
最后上一下老版本的ts编译器生成的__extends函数代码。
var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());};
阅读全文
0 0
- 详解Typescript中继承的实现
- javascript中实现对象继承的五种方式详解
- cocos2dx中lua实现继承详解
- cocos2dx中lua实现继承详解
- cocos2dx中lua实现继承详解
- TypeScript类、接口、继承
- ajax中 实现的继承
- Java中继承的实现
- Typescript实现对table的排序
- TypeScript中API命名重复的解决方法
- 在继承中关于super的详解
- Vscode中Javascript使用TypeScript文件实现智能提示
- 【第4篇】TypeScript类的详解案例代码使用。
- 【第5篇】TypeScript块module的案例代码详解
- 【第6篇】TypeScript函数function的案例代码详解
- 【第7篇】TypeScript泛型的案例代码详解
- 【第8篇】TypeScript的Mixin案例代码详解
- jQuery.js中继承的实现
- 算法--基础算法问题
- hibernate之一级缓存和二级缓存
- 第3章 指令
- S5PV210系列 (裸机十一)之 定时器、看门狗和RTC(一)
- 47题
- 详解Typescript中继承的实现
- C-1
- 九度 题目1342:寻找最长合法括号序列II(25分)
- 搜索 P
- web前端学习
- Fire! UVA
- @SuppressWarnings的使用、作用、用法
- C++上机实验6——数组合并
- Viewport 手机屏幕尺寸--webApp学习(一)