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))();