【问题标题】:jQuery prototype using $(this) and this使用 $(this) 和 this 的 jQuery 原型
【发布时间】:2015-05-24 12:11:32
【问题描述】:

我正在使用 jQuery .prototype 构建一个 jQuery/javascript Web 应用程序。 在下面的代码中,我想更新原型全局值this.score,我必须bind(this) 才能完成这项工作。

如果不绑定this,我可以使用$(this) 到达btnElement 内的跨度,但绑定后这不再起作用。有没有像“这个”这样的解决方法? ;)

showQuestion: function(question) {
   this.quiz.show();

   var btnElement = this.quiz.find('div');
   btnElement.on('click', function() {
        var btn = $(this).find('span');

        if (btn.hasClass('correct')) {
            btn.addClass('good');
            this.score += 1;
        } else {
            $('span.correct').addClass('good');
            btn.addClass('wrong');
        }
   }.bind(this));
}

【问题讨论】:

    标签: jquery oop prototype this bind


    【解决方案1】:

    你已经绑定了你的事件回调,所以它里面的this指的是它外面的this。这意味着您不能在 jQuery 事件处理程序(与事件相关的 DOM 元素)中使用 this 的通常含义。

    三种处理方式:

    1. 请改用btnElement,因为它很方便:

      showQuestion: function(question) {
         this.quiz.show();
      
         var btnElement = this.quiz.find('div');
         btnElement.on('click', function() {
              var btn = btnElement.find('span');   // <====
      
              if (btn.hasClass('correct')) {
                  btn.addClass('good');
                  this.score += 1;
              } else {
                  $('span.correct').addClass('good');
                  btn.addClass('wrong');
              }
         }.bind(this));
      }
      
    2. 使用e.currentTarget,这与未绑定处理程序的this 相同(在这种情况下,您也可以使用e.delegateTarget,因为它不是委托处理程序,因此它是相同的值):

      showQuestion: function(question) {
         this.quiz.show();
      
         var btnElement = this.quiz.find('div');
         btnElement.on('click', function(e) {              // <====
              var btn = $(e.currentTarget).find('span');   // <====
      
              if (btn.hasClass('correct')) {
                  btn.addClass('good');
                  this.score += 1;
              } else {
                  $('span.correct').addClass('good');
                  btn.addClass('wrong');
              }
         }.bind(this));
      }
      

      我没有推荐e.target,因为它完全是一回事:e.target 是事件发生的元素; this 是您让事件挂钩的元素。所以e.target 可能是您测验的div后代元素。

    3. 不要绑定事件处理程序,而是将this 的引用存储在事件处理程序关闭的变量中:

      showQuestion: function(question) {
         var self = this;                        // <====
      
         self.quiz.show();
      
         var btnElement = this.quiz.find('div');
         btnElement.on('click', function() {
              var btn = $(this).find('span');
      
              if (btn.hasClass('correct')) {
                  btn.addClass('good');
                  self.score += 1;                // <====
              } else {
                  $('span.correct').addClass('good');
                  btn.addClass('wrong');
              }
         });                                      // <====
      }
      

    【讨论】:

    • 我猜应该是e.target而不是e.delegateTarget
    • @A.Wolff:哦哦!我总是忘记 jQuery 的 delegateTarget!
    • @A.Wolff:虽然实际上e.currentTarget 是最合适的——但我也总是忘记currentTarget,所以再次感谢。但是是的,e.delegateTarget 与非委托处理程序中的e.currentTarget 相同。
    • 是的,确实更有意义
    • @ronnyrr:第三个例子没什么问题,这是很常见的做法。但为此,我倾向于#2,因为您至少 possible 为 JavaScript 编译器(浏览器可能有一个即时编译器,而不是解释器)为showQuestion 的函数调用上下文回收内存,即使从技术上讲,您在那里有一个可以在调用中幸存的闭包(因此通常会保留它):您没有在您的内部使用btnQuestionquestion处理程序,因此一个真正智能的引擎可能能够优化它。但这不太重要。
    【解决方案2】:

    一种方法是在点击处理程序之外绑定并使用对this的引用

    showQuestion: function(question) {
       this.quiz.show();
    
       var btnElement = this.quiz.find('div');
       var self = this; // create a reference to this
       btnElement.on('click', function() {
            var btn = $(this).find('span'); // you will still be able to find the span which is inside the btnElement
    
            if (btn.hasClass('correct')) {
                btn.addClass('good');
                self.score += 1; // you will still be able to refer this which is reference as self outside
            } else {
                $('span.correct').addClass('good');
                btn.addClass('wrong');
            }
       });
    }
    

    其他方法是向bind发送参数(除了其他答案中的所有其他选项)

    showQuestion: function(question) {
       this.quiz.show();
    
       var btnElement = this.quiz.find('div');
       btnElement.on('click', function(event, btnElement) { // 
            var btn = btnElement.find('span'); 
            if (btn.hasClass('correct')) {
                btn.addClass('good');
                this.score += 1; 
            } else {
                $('span.correct').addClass('good');
                btn.addClass('wrong');
            }
       }.bind(this, btnElement));
    }
    

    这也很有效,只是将按钮引用发送到它自己的点击处理程序有点奇怪。

    【讨论】:

    • 很棒的解决方法,感谢您解决了我的问题! ;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-26
    • 2011-04-07
    • 1970-01-01
    • 2016-03-31
    • 2011-07-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多