JS类以面向对象的形式继承
JS类以面向对象的方式继承
场景:项目环境中使用了SeaJS做模块化加载,每个js文件是相对独立的一个模块,模块之间的耦合度降低了,但是它没有提供JS类之间的继承机制。怎样通过类继承的方式打通类之间的关联,充分使用对象对象带来的好处呢,可以参考motools( http://mootools.net/ )提供的类继承机制。
motools在提供了类继承机制的同时也扩展了很多JS底层的类和方法,扩展的类和方法在不以motools为js基础库的项目中很少用到或没有用。所以对motools的源码进行了精简,只保留了JS类继承相关的代码。如下:
(function() { Function.prototype.overloadSetter = function(usePlural) { var self = this; return function(a, b) { if (a == null) return this; //如果不是字符串,则遍历所有的key,分别设置key对应的值 if (usePlural || typeof a != 'string') { for ( var k in a){ self.call(this, k, a[k]); } } else { self.call(this, a, b); } return this; }; }; //为当前类添加属性 Function.prototype.extend = function(key, value) { this[key] = value; }.overloadSetter(); //为父类添加属性 Function.prototype.implement = function(key, value) { this.prototype[key] = value; }.overloadSetter(); //类型判断方法 var typeOf = this.typeOf = function(item) { if (item == null){ return 'null'; } //判断是否为数组 if(item && typeof item =="object" && Object.prototype.toString.call(item)=='[object Array]'){ return 'array' ; } return typeof item; }; //基本的扩展方法 var cloneOf = function(item) { switch (typeOf(item)) { case 'array': return item.clone(); case 'object': return Object.clone(item); default: return item; } }; //为Array添加clone方法 Array.implement({ clone : function() { var i = this.length, clone = new Array(i); while (i--) clone[i] = cloneOf(this[i]); return clone; } , append : function(array) { this.push.apply(this, array); return this; } }); var mergeOne = function(source, key, current) { switch (typeOf(current)) { case 'object': if (typeOf(source[key]) == 'object') Object.merge(source[key], current); else source[key] = Object.clone(current); break; case 'array': source[key] = current.clone(); break; default: source[key] = current; } return source; }; Object.extend({ merge : function(source, k, v) { if (typeof k == 'string'){ return mergeOne(source, k, v); } for (var i = 1, l = arguments.length; i < l; i++) { var object = arguments[i]; for ( var key in object) mergeOne(source, key, object[key]); } return source; }, clone : function(object) { var clone = {}; for ( var key in object) clone[key] = cloneOf(object[key]); return clone; }, append : function(original) { for (var i = 1, l = arguments.length; i < l; i++) { var extended = arguments[i] || {}; for ( var key in extended) original[key] = extended[key]; } return original; } }); //创建class对象 var Class = this.Class = function(params) { //如果类的参数为一个函数,则将函数定义为构造方法 if ((typeof params) == 'function'){ params = { initialize : params }; } //newClass扩展了类Class和参数的所有属性。Class是定义中声明的,参数是构造对象时传入的。 //注:可以看到构造函数的参数和类的构造参数相同。 var newClass = function() { reset(this); if (newClass.$prototyping){ return this; } this.$caller = null; //调用initialize方法 var value = (this.initialize) ? this.initialize.apply(this,arguments) : this ; this.$caller = this.caller = null; return value; }.extend(this).implement(params); newClass.$constructor = Class ; newClass.prototype.$constructor = newClass ; newClass.prototype.parent = parent ; return newClass; } ; var parent = function() { if (!this.$caller) throw new Error('The method "parent" cannot be called.'); var name = this.$caller.$name, parent = this.$caller.$owner.parent, previous = (parent) ? parent.prototype[name] : null; if (!previous) throw new Error('The method "' + name + '" has no parent.'); return previous.apply(this, arguments); }; //重置对象,如果为object,则构造一个中间类,创建新的对象 var reset = function(object) { for ( var key in object) { var value = object[key]; switch (typeOf(value)) { case 'object': var F = function() { }; F.prototype = value; object[key] = reset(new F); break; case 'array': object[key] = value.clone(); break; } } return object; }; //对函数的重包装,实际上还是调用原来的方法 var wrap = function(self, key, method) { if (method.$origin) method = method.$origin; var wrapper = function() { if (method.$protected && this.$caller == null) throw new Error('The method "' + key + '" cannot be called.'); var caller = this.caller, current = this.$caller; this.caller = current; this.$caller = wrapper; var result = method.apply(this, arguments); this.$caller = current; this.caller = caller; return result; }.extend({ $owner : self, $origin : method, $name : key }); return wrapper; }; //实现属性的赋值 var implement = function(key, value, retain) { if (Class.Mutators.hasOwnProperty(key)) { value = Class.Mutators[key].call(this, value); if (value == null){ return this; } } if (typeOf(value) == 'function') { if (value.$hidden){ return this; } this.prototype[key] = (retain) ? value : wrap(this, key, value); } else { Object.merge(this.prototype, key, value); } return this; }; /** * 获取实例化的对象 */ var getInstance = function(klass) { klass.$prototyping = true; var proto = new klass; delete klass.$prototyping; return proto; }; //为class添加或覆盖implement方法 Class.implement('implement', implement.overloadSetter()); Class.Mutators = { Extends : function(parent) { this.parent = parent; this.prototype = getInstance(parent); }, Implements : function(items) { if(!items){ return ; } //将items转换为数组 if(typeOf(items)!='array'){ items = [items] ; } for (var i = 0; i < items.length; i++) { var item = items[i] ; var instance = new item; for ( var key in instance){ implement.call(this, key, instance[key], true); } } } }; //属性类 this.Options = new Class({ setOptions : function() { //合并当前对象的options和传入的options参数 var options = this.options = Object.merge.apply(null, [ {},this.options ].append(arguments)); return this; } }); //在window命名空间下运行 }.bind(window))();