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 に答える