سؤال

var PlaylistView = Backbone.View.extend({
  el: '#expanded-container',

  initialize: function() {
    this.bg = chrome.extension.getBackgroundPage();
    this.$('.list-group').empty();
    var realThis = this;
    _.each(this.bg.Playlist.models, function (song) {
      // append to playlist, rendering song template?
      var songView = new SongView({ model: song });
      console.log(realThis); // THIS is what I want
      console.log(this) // this is NOT what I want
      //this.$el.append(songView.render().el); // hence, this does NOT work
      realThis.$el.append(songView.render().el); // and THIS works
    });
  }
});

In the above code, this inside _.each() function points at the global window object because _.each() is invoked by the window. However, I still want this to point at PlaylistView. I have faced many similar situations and I often defined a variable that stored the initial value of this, just like realThis variable in the provided example. Is there any other conventional way to deal with this?

Note: I am following this book to learn Backbone, and it shows the following code as example.

var ListView = Backbone.View.extend({
  render: function(){

    // Assume our model exposes the items we will
    // display in our list
    var items = this.model.get('items');

    // Loop through each of our items using the Underscore
    // _.each iterator
    _.each(items, function(item){

      // Create a new instance of the ItemView, passing 
      // it a specific model item
      var itemView = new ItemView({ model: item });
      // The itemView's DOM element is appended after it
      // has been rendered. Here, the 'return this' is helpful
      // as the itemView renders its model. Later, we ask for 
      // its output ("el")
      this.$el.append( itemView.render().el ); // <--- *THIS IS WRONG?
    }, this);
  }
});

In this case, wouldn't this inside _.each loop point at the wrong object, just like in my code? Is this an error in the book or am I misunderstanding something? Thank you!

Reference: Learning this keyword

هل كانت مفيدة؟

المحلول 2

You can change this of a particular function by using .bind():

function foo() {
    alert(this.x);
}
var boundFoo = foo.bind({x: "bar"});
boundFoo();

This alerts "bar".

Saving the outer this as realThis or that is also common if you want access to both the inner and outer this.

Underscore uses .call() to change this of the iterator function you pass it. Specifically, _.each() has a third parameter that allows you to specify what you want this to be, so that example is correct. See the underscore.js source.

نصائح أخرى

From http://underscorejs.org/#each:

each _.each(list, iterator, [context])

The iterator is bound to the context object, if one is passed.

Within initialize(), this points to your Backbone View. If you pass this as the 3rd argument to _.each() then this will refer to your Backbone View within the iterator function.

I have faced many similar situations and I often defined a variable that stored the initial value of this, just like realThis variable in the provided example. Is there any other conventional way to deal with this?

Yes. If you are in an ES5 (non-IE8) environment, use Function.prototype.bind(). For backwards compatibility, use _.bind().

var func = function (greeting) {
  return greeting + ': ' + this.name;
};

if (usingUnderscore) {
  func = _.bind(func, {name: 'moe'}, 'hi');
} else if (es5environmentHooray) {
  func = func.bind({name: 'moe'}, 'hi');
}

func();
=> 'hi: moe'
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top