【问题标题】:Why does 'this' get bound to the window inside the object's closure after backbone's model.fetch?为什么在主干的model.fetch之后'this'会绑定到对象闭包内的窗口?
【发布时间】:2012-08-04 04:02:44
【问题描述】:

所以我有这个看起来像这样的 javascript/Backbone 脚本:

var Model = Backbone.Model.extend({});

var View = Backbone.View.extend({

 initialize: function() {
    _.bindAll(this); //bind this
   this.doProcessing();
 },

 doProcessing: function() {

  $('.someElement').each(function() {
      Model myModel = new Model;
      myModel.fetch({                          //issue ajax
         success: function(model, response){   //after successful ajax
            console.log(this)                  // <-- outputs Window!!
       });     

   }); //end each

  } //end processing

});

new View;

让我不解的是this 是如何绑定到窗口的。我很清楚我的关闭,但 this 不应该引用 model 吗?

这就是我的理解 - 成功回调以某种方式绑定到 Window 对象。因此,当它被调用时,上下文就是窗口对象的上下文。但在我看来,这有点出乎意料。骨干为什么这样做的任何原因(或者我误解了什么?)。

通过successmodel参数设置myModel的属性有点奇怪。当它应该允许一个简单的this.set({...}) 时,调用model.set({...}) 似乎很复杂

在这种情况下,我对this 的理解是否正确?任何解决方法?或者这更像是 XHR 绑定到成功回调的方式?

来自 Backbone 的源代码 (Model.fetch):

fetch: function(options) {
      options = options ? _.clone(options) : {}; //cloning options - does this variable get bound to global?
      var model = this;
      var success = options.success;            //or is it this?
      options.success = function(resp, status, xhr) {
        if (!model.set(model.parse(resp, xhr), options)) return false;
        if (success) success(model, resp);
      };
      options.error = Backbone.wrapError(options.error, model, options);
      return (this.sync || Backbone.sync).call(this, 'read', this, options);
    },

【问题讨论】:

    标签: javascript ajax backbone.js closures this


    【解决方案1】:

    “成功回调以某种方式绑定到窗口对象”

    不,JavaScript 中的函数没有“绑定”。 this 仅在调用函数时指定。我们来看看它是怎么称呼的

    success(model, resp)
    

    所以函数是直接调用的,不是通过方法调用语法(someObj.someMethod(...)),也不是通过.call().apply()。所以在本例中,this 设置为全局对象,在本例中为窗口。

    【讨论】:

      【解决方案2】:

      一种解决方法是尝试这样的方法

      myModel.fetch({                          
           success: _.bind(function(model, response){   
              console.log(this);                  
         },this);
      });     
      

      【讨论】:

      • 似乎不起作用。输出是 each 正在迭代的 div 元素,但不是 myModel
      • 如果您将 this 更改为 myModel 作为要绑定的最后一个参数,则可以使用。但这不是有点难看吗?
      【解决方案3】:

      默认情况下会发生这种情况,因为 .call() 或 .apply() 没有给出任何特定的上下文,它回退到使用 window 作为 this 对象

      【讨论】:

      • 你在哪里看到的?如果我理解正确,对call 的调用包括this 作为上下文
      • 没有call 正在完成...您的成功处理程序只是被定期调用:if (success) success(model, resp);
      【解决方案4】:

      块的上下文,或者this所引用的内容在javascript中是非常volatile的。

      我认为上下文的更改是在 $('.someElement').each(function() { ... }); 块中完成的,与 Model.fetch() 的工作方式无关。

      尝试添加更多日志,例如:

      doProcessing: function() {
        console.log( "out of the block", this );
      
        $('.someElement').each(function() {
          console.log( "begining of block", this );
      
          Model myModel = new Model;
          myModel.fetch({                          
            success: function(model, response){ 
              console.log( "into the fetch", this );                 
            }     
          });
        };
      
        console.log( "end of block", this );
      }
      

      进入eachthis应该是真正进入循环的DOM元素。

      为了解决this 的这种变化,这意味着我习惯使用的一种解决方法,并且我习惯于看到周围的情况是将this 引用到 之外的另一个变量(当 this 是您所期望的)并将这个新引用用于块中:

      doProcessing: function() {
        console.log( "out of the block", this );
      
        var _self = this;
      
        $('.someElement').each(function() {
          console.log( "begining of block", _self );
      
          Model myModel = new Model;
          myModel.fetch({                          
            success: function(model, response){ 
              console.log( "into the fetch", _self );
            }     
          });
        };
      
        console.log( "end of block", this );
      }
      

      更新

      如果您想要引用您最近创建的模型,只需使用您创建的外部引用,如下所示:

      doProcessing: function() {
        $('.someElement').each(function() {
          Model myModel = new Model;
          myModel.fetch({                          
            success: function(model, response){ 
              console.log( "into the fetch", myModel );                 
            }     
          });
        };
      }
      

      或者只是使用 Backbone 发送到 成功回调的引用:

      doProcessing: function() {
        $('.someElement').each(function() {
          Model myModel = new Model;
          myModel.fetch({                          
            success: function(model, response){ 
              console.log( "into the fetch", model );                 
            }     
          });
        };
      }
      

      【讨论】:

      • 是的,我确实使用它。但这不是重点。 _self 指的是最外面的对象,not 指的是myModel
      • @PhD 答案已更新,向您展示如何传递对最近创建的模型的引用
      猜你喜欢
      • 2017-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-08
      • 2018-09-14
      • 2012-12-14
      • 2012-07-01
      • 1970-01-01
      相关资源
      最近更新 更多