1

我正在从原型切换到 jquery,并且我正在努力使用“最佳”对象/类表示法。最困扰我的是“this”上下文,当在回调函数(例如事件处理程序,甚至 jquery 的 .each() 方法)中使用时,它不允许我访问对象本身。在原型中我使用 .bind() 或 .bindAsEventListener(),但在 jquery 中我发现只有以下方法:1) 缓存对象指针(在文字表示法中对我来说效果不佳) 2) 使用 $.proxy()方法我发现这两种方法都非常不优雅/丑陋。我有 2 个相同功能的变体(简单的弹出窗口),请告诉我您更喜欢哪一个,以及为什么。或者,您可以提出一些改进建议。非常感谢您的帮助。

变体1:

Dialog = function(container, callback) {
  this.init(container, callback);
}

$.extend(Dialog.prototype, {
   init: function(container, callback) {
     this.dialog = $(container);
     this.callback = callback;
     this.buttons = {
       ok: this.dialog.find('[data-type="ok"]'),
       cancel: this.dialog.find('[data-type="cancel"]')
     }
     $.each(this.buttons, $.proxy(function(key, button) {
       button.click($.proxy(function() { this.hide(key); }, this));
     }, this));
   },

   show: function() {
     this.dialog.show();
   },

   hide: function(key) {
     this.dialog.hide();
     this.callback(key);
   }   
});

变体 2:

function Dialog2(container, callback) {
  var self = this;
  self.dialog = $(container);
  self.callback = callback;
  self.buttons = {
    ok: self.dialog.find('[data-type="ok"]'),
    cancel: self.dialog.find('[data-type="cancel"]')
  }
  $.each(self.buttons, function(key, button) {
    button.click(function() { self.hide(key); });
  });

  self.show = function() {
    self.dialog.show();
  }

  self.hide = function(key) {
    self.dialog.hide();
    self.callback(key);
  }
}

使用例如创建实例:

var dialog = new Dialog($('#dialog'), function(result){ alert(result); });
dialog.show();

(另外,我不太确定,为什么在变体 1 中,“this.dialog”是在块“this.buttons = { ... }”中定义的。我建议嵌套对象中的“this”指向匿名嵌套对象本身...)

4

1 回答 1

1

必须有几乎无数种方法来解决这个问题。

绝对避免使用嵌套$.proxy(),这会让经验不足的程序员在未来可能需要维护您的代码,而更有经验的程序员会问“为什么?”。

坚持 POJS 构造函数的想法,您this几乎可以完全避免通过编写带有私有成员的整个构造函数,this...并在末尾加上几个以将某些函数公开为公共方法。

(未经测试):

var Dialog = function(container, callback) {
    //define private members
    var dialog, buttons;
    var init = function() {
        dialog = $(container);
        buttons = {
            ok: dialog.find('[data-type="ok"]'),
            cancel: dialog.find('[data-type="cancel"]')
        };
        $.each(buttons, function(key, button) {
            button.on('click', function() {
                hide(key);
            });
        });
    };
    var show = function() {
        dialog.show();
    };
    var hide = function(key) {
        dialog.hide();
        callback(key);
    };

    //initialize
    init();

    //expose public methods
    this.show = show;
    this.hide = hide;
}

请注意私有函数如何直接访问其他私有成员,包括其他私有函数和实例化时传递的形式变量。公共方法只是对私有函数的引用。

远离简单的构造函数,您可能需要考虑:

插件可能看起来像这样(未经测试):

(function($){
    // **********************************
    // ***** Start: Private Members *****
    var pluginName = 'dialog';
    // ***** Fin: Private Members *****
    // ********************************

    // *********************************
    // ***** Start: Public Methods *****
    var methods = {
        init : function(options) {
            //"this" is a jquery object on which this plugin has been invoked.
            return this.each(function(index){
                var $this = $(this);
                var data = $this.data(pluginName);
                // If the plugin hasn't been initialized yet
                if (!data){
                    var settings = {
                        callback: function(){}
                    };
                    if(options) { $.extend(true, settings, options); }

                    var buttons = {
                        ok: $this.find('[data-type="ok"]'),
                        cancel: $this.find('[data-type="cancel"]')
                    };
                    $.each(buttons, function(key, button) {
                        $this.on('click', button, function() {
                            methods.hide.call($this, key);
                        });
                    });

                    $this.data(pluginName, {
                        target : $this,
                        settings: settings
                    });
                }
            });
        },
        show: function() {
            return this.each(function(index){
                $(this).show();
            });
        },
        hide: function(key) {
            return this.each(function(index){
                $(this).hide().data(pluginName).settings.callback(key);
            });
        }
    };
    // ***** Fin: Public Methods *****
    // *******************************

    // *****************************
    // ***** Start: Supervisor *****
    $.fn[pluginName] = function( method ) {
        if ( methods[method] ) {
            return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
        } else if ( typeof method === 'object' || !method ) {
            return methods.init.apply( this, arguments );
        } else {
            $.error( 'Method ' + method + ' does not exist in jQuery.' + pluginName );
        }
    };
    // ***** Fin: Supervisor *****
    // ***************************
})( jQuery );
于 2012-09-26T00:35:29.263 回答