上文《详解Javascript的继承实现》介绍了一个通用的继承库,基于该库,可以快速构建带继承关系和静态成员的javascript类,好使用也好理解,额外的好处是,如果所有类都用这种库来构建,还能使代码在整体上保持一致的风格,便于其它同事阅读和理解。在写完该文之后,这两天时不时都 ...
上文《详解Javascript的继承实现》介绍了一个通用的继承库,基于该库,可以快速构建带继承关系和静态成员的javascript类,好使用也好理解,额外的好处是,如果所有类都用这种库来构建,还能使代码在整体上保持一致的风格,便于其它同事阅读和理解。在写完该文之后,这两天时不时都在思考这个库可能存在的问题,加上这两天又在温习《JavaScript面向对象编程指南》这本书继承这一章的内容,发现对继承的内容有了一些新的发现和理解,有必要再把这两天的收获再分享出来。
1. 继承库的注意事项
为了方便阅读本部分的内容,只好先把上文继承库的实现代码和演示代码再搬出来,省的还得回到那篇文章去找相关内容,好在代码我加了折叠的功能,即使不想展开看,也不会太影响阅读:
//继承库实现部分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 copy(source) { var target = {}; for (var i in source) { if (hasOwn.call(source, i)) { target[i] = source[i]; } } return target; } 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 (extend) { //如果有要继承的父类 //就在每个实例中添加baseProto属性,以便实例内部可以通过这个属性访问到父类的原型 //因为copy函数导致原型链断裂,无法通过原型链访问到父类的原型 this.baseProto = extend.prototype; } if (isFunction(this.init)) { this.init.apply(this, arguments); } } //添加静态成员,这段代码需在原型设置的前面执行,避免staticMembers中包含prototype属性,覆盖类的原型 for (prop in staticMembers) { if (hasOwn.call(staticMembers, prop)) { TargetClass[prop] = staticMembers[prop]; } } //如果有要继承的父类,先把父类的实例方法都复制过来 extend && (TargetClass.prototype = copy(extend.prototype)); //添加实例方法 for (prop in instanceMembers) { if (hasOwn.call(instanceMembers, prop)) { //如果有要继承的父类,且在父类的原型上存在当前实例方法同名的方法 if (extend && isFunction(instanceMembers[prop]) && isFunction(extend.prototype[prop])) { TargetClass.prototype[prop] = (function (name, func) { return function () { //记录实例原有的this.base的值 var old = this.base; //将实例的this.base指向父类的原型的同名方法 this.base = extend.prototype[name]; //调用子类自身定义的实例方法,也就是func参数传递进来的函数 var ret = func.apply(this, arguments); //还原实例原有的this.base的值 this.base = old; return ret; } })(prop, instanceMembers[prop]); } else { TargetClass.prototype[prop] = instanceMembers[prop]; } } } TargetClass.prototype.constructor = TargetClass; return TargetClass; } return ClassBuilder})();//继承库演示部分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 Manager = Class({ instanceMembers: { init: function (name, salary, percentage) { //通过this.base调用父类的构造方法 this.base(name, salary); this.percentage = percentage; }, getSalary: function () { return this.base() + this.salary * this.percentage; } }, extend: Employee});var e = new Employee('jason', 5000);var m = new Manager('tom', 8000, 0.15);console.log(e.toString()); //jason's salary is 5000.console.log(m.toString()); //tom's salary is 9200.console.log(e.constructor === Employee); //trueconsole.log(m.constructor === Manager); //trueconsole.log(e.id); //1console.log(m.id); //2
原标题:详解Javascript的继承实现(二)
关键词:JavaScript
*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们:
admin#shaoqun.com
(#换成@)。