详解Javascript继承的实现(5)

从第1部分的分析可以看出,在js里面,类的构建与继承,有很多通用的逻辑,完全可以把这些逻辑封装成一个单独的模块,形成一个通用的类库,以便在工作中有需要的时候,都可以直接拿来使用。这个类库要求能完成我们需要的功能(类的构建与继承和静态成员的添加),同时在使用时要足够简洁方便。在利用bootstrap的modal组件自定义alert,confirm和modal对话框这篇文章里,我曾说过一些从组件期望的调用方式,去反推组件实现的一些观点,当你明确你需要什么东西时,你才知道这个东西你该怎么去创造。本文要编写的这个继承组件也会采取这个方法来实现,我先用前面Employee和Manager的例子来模拟调用这个继承库的场景,通过预设的一些组件名称或者接口名称以及调用方式,来尝试走通真实使用这个继承库的流程,有了这个东西,下一步我只需要根据这个要求去实现即可,模拟如下:

- Hide code //通过调用Class函数构造一个类 var Employee = Class({ //通过instanceMembers指定这个类的实例成员 instanceMembers: { init: function (name, salary) { this.name = name; this.salary = salary; //调用静态方法 this.id = Employee.getId(); }, getName: function () { return this.name; }, getSalary: function () { return this.salary; }, toString: function () { return this.name + '\'s salary is ' + this.getSalary() + '.'; } }, //通过staticMembers指定这个类的静态成员 //静态方法内部可通过this访问其它静态成员 //在外部可通过Employee.getId这种方式访问到静态成员 staticMembers: { idCounter: 1, getId: function () { return this.idCounter++; } } }); var Manager = Class({ instanceMembers: { init: function (name, salary, percentage) { this.base(name, salary); this.percentage = percentage; Manager.count++; }, getSalary: function () { return this.salary + this.salary * this.percentage; } }, //通过extend指定要继承的类 extend: Employee });

从模拟的结果来看,我想要的继承库对外提供的名称只有Class, instanceMembers, staticMembers和extend而已,调用方式也很简单,只要传递参数给Class函数即可。接下来就按照这个目标,看看如何一步步根据第一部分罗列的那些问题和解决方式,把这个库给写出来。

3. 继承库的详细实现

根据API名称和接口以及前面第1部分提出的问题,这个继承库要完成的功能有:
1)类的构建(关键:init方法)和静态成员处理;
2)继承关系的构建(关键:父类原型的复制);
3)父类方法的简化调用(关键:父类原型上同名方法的代理)。
所以这个库的实现,可以按照这三点分成三版来开发。

1)第一版

在第一版里面,仅需要实现类的构架和静态成员添加的功能即可,细节如下:

- Hide code var Class = (function () { var hasOwn = Object.prototype.hasOwnProperty; //用来判断是否为Object的实例 function isObject(o) { return typeof (o) === 'object'; } //用来判断是否为Function的实例 function isFunction(f) { return typeof (f) === 'function'; } function ClassBuilder(options) { if (!isObject(options)) { throw new Error('Class options must be an valid object instance!'); } var instanceMembers = isObject(options) && options.instanceMembers || {}, staticMembers = isObject(options) && options.staticMembers || {}, extend = isObject(options) && isFunction(options.extend) && options.extend, prop; //表示要构建的类的构造函数 function TargetClass() { if (isFunction(this.init)) { this.init.apply(this, arguments); } } //添加静态成员,这段代码需在原型设置的前面执行,避免staticMembers中包含prototype属性,覆盖类的原型 for (prop in staticMembers) { if (hasOwn.call(staticMembers, prop)) { TargetClass[prop] = staticMembers[prop]; } } TargetClass.prototype = instanceMembers; TargetClass.prototype.constructor = TargetClass; return TargetClass; } return ClassBuilder })();

这一版核心代码在于类的构建和静态成员添加的部分,其它代码仅仅提供一些提前可以想到的赋值函数和变量(isObject, isFunction),并做一些参数合法性校验的处理。添加静态成员的代码一定要在设置原型的代码之前,否则就有原型被覆盖的风险。有了这个版本,就可以直接构建带静态成员的Employee类了:

- Hide code var Employee = Class({ instanceMembers: { init: function (name, salary) { this.name = name; this.salary = salary; //调用静态方法 this.id = Employee.getId(); }, getName: function () { return this.name; }, getSalary: function () { return this.salary; }, toString: function () { return this.name + '\'s salary is ' + this.getSalary() + '.'; } }, staticMembers: { idCounter: 1, getId: function () { return this.idCounter++; } } }); var e = new Employee('jason', 5000); console.log(e.toString()); //jason's salary is 5000. console.log(e.id); //1 console.log(e.constructor === Employee); //true

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wgydxg.html