您的位置:首页 > Web前端 > JavaScript

JS类以面向对象的方式继承

2015-08-20 09:09 543 查看

       场景:项目环境中使用了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))();

 

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: