JavaScript模拟Java类继承
javascript采用原型继承的方式继承一个类(javascript没有类这个概念,暂时这么称呼吧),但一些使用过Java的程序员可能习惯使用经典的类继承,但javascript原生并不支持这种方式,因此需要手动实现。这里通过定义一个定义类(defineClass)的函数实现,经测试越用越顺手。由于javascript没有访问修饰符,因此如果需要使用到private成员,请使用闭包。
1 /* 简单的对象扩充方法 2 */ 3 merge:function (target, origin) { 4 for (var attribute in origin) { 5 if (origin.hasOwnProperty(attribute)) { 6 target[attribute] = origin[attribute]; 7 } 8 } 9 }, 10 defineClass:function defineClass(constructor, parent, properties, statics, isSingleton) { 11 12 /* 如果为单例模式,保存实例,并在以后的调用中返回此实例 13 */ 14 if (isSingleton) { 15 var oldConstructor = constructor, 16 instance; 17 constructor = function () { 18 if (instance) return instance; 19 oldConstructor.apply(this, arguments); 20 instance = this; 21 } 22 } 23 24 /* 设置原型属性,这意味着传入的构造函数的原型属性将被覆盖 25 * 重要:parent内部需要检测参数,下面将会讲到 26 */ 27 constructor.prototype = parent ? new parent() : {}; 28 29 /* 将自有属性复制到原型中 30 * 将静态属性复制到构造函数中,这意味着将不会继承parent的静态属性 31 */ 32 Lang.merge(constructor.prototype, properties); 33 Lang.merge(constructor, statics); 34 35 /* 将构造函数更改为当前构造函数 36 * 将parent的引用保留 37 */ 38 constructor.prototype.constructor = constructor; 39 constructor.prototype.parent = parent; 40 constructor.parent = parent; 41 42 /* 借用父类函数 43 */ 44 constructor.borrow = function(methodName, context, args){ 45 var oldParent; 46 47 if(typeof methodName === "object") { 48 args = context; 49 context = methodName; 50 } 51 52 oldParent = context.parent; 53 context.parent = parent; 54 55 if(typeof methodName === "string") { 56 constructor.prototype[methodName].apply(context, args || []); 57 } else { 58 constructor.apply(context, args || []); 59 } 60 61 context.parent = oldParent; 62 }; 63 return constructor; 64 }
使用时,父类如此定义
1 var Body = Lang.defineClass(function(x, y, shapes, sprites, detection){ 2 /* 由于类定义函数会创建父类实例作为子类的原型,因此必须检测参数 3 * 如果没有参数,相当于调用父类的默认构造函数 4 */ 5 if(arguments.length) { 6 /* 使用父类方法 7 */ 8 this.parent.borrow(this, arguments); 9 10 /* 非基本类型请放到构造函数中而不是原型中 11 */ 12 this._tasks = []; 13 } 14 }, Object, { 15 _distance: 0, 16 setX: function(x){}, 17 setY: function(y){} 18 }, { 19 type: ‘Base‘ 20 });
继承Body
1 var Ninja = Lang.defineClass(function(){ 2 this.parent.borrow(this, arguments); 3 }, Body, { 4 _status: 1, 5 setStatus: function(x){ 6 /* 使用父类方法 7 */ 8 this.parent.borrow(‘setStatus‘, this, arguments); 9 } 10 }, {});
注意,不能用此方法继承如Array等内置对象,如果你想通过定义一个类扩展Array的功能,那么在调用Array的某些方法时会出现问题,比如concat返回的数组直接包含两个对象,而不是包含两个对象中的元素。原因是虽然子类的原型链包含Array.prototype,但毕竟不是由Array直接构造,在调用某些方法时可能不会按照原始的方式执行。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。