jquery中的“最佳”对象表示法/上下文绑定

时间:2012-09-25 21:38:48

标签: javascript jquery oop

我正在从原型切换到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”指向匿名嵌套对象本身...)

1 个答案:

答案 0 :(得分: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 );