【发布时间】:2011-04-21 22:10:22
【问题描述】:
我最近编写了一个类创建脚本(在 Crockford 和 Resig 的某些部分的代码的帮助下),它可以自动执行某些任务,例如:将默认值与传入的参数合并、需要参数、在 DOM 和类实例之间创建桥梁、绑定具有公共命名空间的自定义事件、可访问超级方法的继承以及混合功能。
我的第一个问题是,以这种方式创建课程的优缺点是什么?我关心的是性能和可移植性(现在我所有的类都依赖于这个脚本)。
我的第二个问题是,编写类创建脚本的更好方法是什么?代码如下。
(function($){
// Crockford's way of creating new objects
function F(){};
function _createObject(o) {
F.prototype = o;
return new F();
};
$.Class = function(){
var
prototype = {}
,_super = {}
,requiredError = ''
,extendedInits = []
,fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// copy properties/methods to prototype
for (var i = 0, ln = arguments.length; i < ln; ++i){
var obj = arguments[i];
// if extending another class
if ($.isFunction(obj)) _super = obj = obj.prototype;
if (typeof obj == 'object'){
for (var prop in obj){
var objMethod = obj[prop];
// Resig's Simple Javascript Inheritance
// if method already exists, map old method to this._super()
prototype[prop] = typeof objMethod == "function" && typeof _super[prop] == "function" && fnTest.test(obj[prop]) ?
(function(prop, fn){
return function() {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[prop];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(prop, objMethod) :
// or overwrite the method/property
objMethod;
// if __init method is defined on any of the objects passed in, they will be automatically run at instantiation
if (prop == '__init') extendedInits.push(obj[prop]);
}
}
}
prototype.__initialize = function(){
var
self = this
,dataNS = this.__dataNS
,requiredParams = this.__requiredParams;
// check required parameters
if (requiredParams){
for (var i = 0, ln = requiredParams.length; i < ln; ++i){
var param = requiredParams[i];
if (arguments.length == 0 || !arguments[0][param]) requiredError = requiredError + param + ', ';
}
}
// if all required params are passed in
if (requiredError.length == 0){
// set defaults
this.cfg = $.extend(true, {}, this.__defaults, arguments[0]);
this.$elem = this.cfg.$elem;
// create bridge between dom and instance
if (dataNS) this.$elem.data(dataNS, this);
// init class instance
if (this.init) this.init.apply(this, arguments);
// init objects instance was extended with
if (extendedInits.length > 0){
$.each(extendedInits, function(k, fn){
fn.apply(self, arguments);
});
}
// init instance level
if (this.cfg.__init) this.cfg.__init.apply(this, arguments);
}
else {
// alert missing properties
requiredError = requiredError.substring(0, requiredError.lastIndexOf(','));
var str = 'Required Parameters: ' + requiredError;
if (dataNS) str = dataNS + ' - ' + str;
alert(str);
}
};
function _Class(){
this.__initialize.apply(this, arguments);
}
_Class.prototype = _createObject(prototype);
_Class.constructor = _Class;
return _Class;
}
})(jQuery);
这就是它的使用方式:
$.Accordion = new $.Class({
__requiredParams: ['$elem']
,__defaults: {
speed: 200,
onlyOneOpen: true,
classNames: {
panel: 'panel', panelHeader: 'panelHeader', panelContent: 'panelContent'
}
}
,panels: {}
,init: function(opts){
console.log('1st init');
var self = this;
// loop thru panels
this.$elem.find('.' + this.cfg.classNames.panel).each(function(){
var $this = $(this);
var panelName = $this.attr('id');
// uses panel dom element id as name
self.panels[panelName] = new $.Panel({$elem: $this});
});
// panel header on click
this.$elem.find('.' + this.cfg.classNames.panelHeader).click(function(e){
e.preventDefault();
var panelName = $(this).parents('.' + self.cfg.classNames.panel).attr('id');
var action = (self.panels[panelName].isOpen()) ? 'close' : 'open';
self[action](panelName);
});
}
,closeAll: function(){
$.dispatch('close.panel.accordion');
}
,openAll: function(){
$.dispatch('open.panel.accordion');
}
,open: function(panelName){
if (this.cfg.onlyOneOpen) this.closeAll();
if (typeof this.panels[panelName] != 'undefined') $.dispatch('open.' + panelName + '.accordion');
}
,close: function(panelName){
if (typeof this.panels[panelName] != 'undefined') $.dispatch('close.' + panelName + '.accordion');
}
}, $.ClassUtils);
注意:上例中的 $.ClassUtils 是混合到 $.Accordion 类中的一组公共方法
【问题讨论】:
标签: javascript jquery class