Class.Methods是一个方法集合,把经常用到的方法移出函数体是一个陪明的做法,这样不就用每次进入函数体就反复创建它们。
从另一个角度看,Class.Methods是自动执行函数,YUI的人好像把它归类为模块模式,EXT这样的用法很多,把许多变量与只对当前模块有用的方法捆绑在一个闭包中,减少命名冲突。
Class.Methods = (function() { //一系列方法名,可以看到include涉及最多东西 var commons = $w('selfExtended self_extended selfIncluded self_included'), extend = commons.concat($w('prototype parent extend include')), include = commons.concat(['constructor']); //用来清理模块中不需要的方法 //相当于module.without(extend)或module.without(include) function clean_module(module, what) { return Object.without.apply(Object, [module].concat(what == 'e' ? extend : include)); }; return { //方法集合 } })();
上面有些写法很不妥,如 commons.concat(['constructor']),直接commons.concat('constructor')就可以了。不过最大的问题是Object.without方法:
without: function() { var filter = $A(arguments), object = filter.shift(), copy = {}, key; for (key in object) if (!filter.includes(key)) copy[key] = object[key]; return copy; },
在IE下,for...in循环是有许多属性不能遍历出来的,如valueOf、toString……
看inherit方法,它暗中运用了桥梁模式,使用子类与父类的原型不再连在一起。而且通过new原型的方法,比属性拷贝快很多。
inherit: function(parent) { // 获取父类的原型属性 if (parent && parent.prototype) { var s_klass = function() {}; s_klass.prototype = parent.prototype; this.prototype = new s_klass; this.parent = parent; } // 收集父类 this.ancestors = []; while (parent) { this.ancestors.push(parent); parent = parent.parent; } //修正原型上的constructor属性 return this.prototype.constructor = this; },
下面方法为新类扩展静态成员,这是ruby的写法,在jQuery,无论是为jQuery命名空间添加成员还是为jQuery对象添加实例方法都是用extend,比较无言。
extend: function() { $A(arguments).filter(isHash).each(function(module) { //用于实现ruby的那种自扩展机制 var callback = module.selfExtended || module.self_extended; $ext(this, clean_module(module, 'e')); if (callback) callback.call(module, this); }, this); return this; },
include则为新类扩展原型成员,也是ruby的命名方式。在mootools中,则为implement。觉得mootools与rights从ruby中借鉴了不少东西啊。ruby果然是最强的OO脚本语言。
include: function() { //取得所有超类的原型 var ancestors = this.ancestors.map('prototype'), ancestor; //移参数转换为纯对象数组并迭代它们 $A(arguments).filter(isHash).each(function(module) { //用于ruby式的自包含 var callback = module.selfIncluded || module.self_included; //清理一些危险的方法,防止覆盖 module = clean_module(module, 'i'); for (var key in module) { //取得最近的与它有重名方法的祖先 ancestor = ancestors.first(function(proto) { return isFunction(proto[key]); }); //如果有,则重写此方法,返回一个currying this.prototype[key] = !ancestor ? module[key] : (function(name, method, super_method) { return function() { //用于方法链 this.$super = super_method; return method.apply(this, arguments); }; })(key, module[key], ancestor[key]); } //执行自包含 if (callback) callback.call(module, this); }, this); return this; }
此外,Class还有一个方法,不过作为辅助方法,不加入类工厂中的。
//从当前类或其祖先中,寻找特定的属性 Class.findSet = function(object, property) { var upcased = property.toUpperCase(), capcased = property.capitalize(), candidates = [object, object.constructor].concat(object.constructor.ancestors), holder = candidates.first(function(o) { return o && (o[upcased] || o[capcased]) }); return holder ? holder[upcased] || holder[capcased] : null; };