【问题标题】:Pros and Cons of Class Creation Script in Javascript?Javascript 中类创建脚本的优缺点?
【发布时间】: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


    【解决方案1】:

    许多框架都在做你所做的事情。我对此的主要担忧是它试图使 javascript 成为它不是的东西。 Javascript 是原型继承语言。它不是经典的继承语言。

    这并不是说“类管理”库没有用,因为它们有用。关于您的一些反馈:您编写的代码的其他示例使创建类变得更加容易。如果您要这样做,创建类时的最终结果应该类似于

    var myObj =  MyStuff.create({
       prop: prop,
       doSomething: function(){}
     });
    

    据我从您的示例中可以看出,这比您安装的系统更容易阅读,而且输入更少...

    【讨论】:

    • 嗯,我可能遗漏了一些东西,但你的 sn-p 和我的第二个 sn-p 不相似吗?您的示例是定义类本身,而不是实例化一个正确的吗?我见过其他实现使用 Class.create({}) 之类的东西,但我喜欢使用 new 运算符(如果只是出于语义原因)。
    • @alex,啊,我明白你在做什么。你会如何扩展一个类?
    • 这就像 var extendedClass = new $.Class(thisClassJson, classToExtendFrom, secondClassToExtendFrom);所以基本上传入的第一个 json 被用作该类的定义,并且每个其他的都混入
    猜你喜欢
    • 1970-01-01
    • 2011-05-04
    • 2014-06-13
    • 2013-10-11
    • 1970-01-01
    • 2014-01-25
    • 2011-02-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多