Search code examples
javascriptbackbone.jsunderscore.js

Why 'without' method returns different results depending on context?


I want to filter a Backbone collection using _.without method.

It returns correct results (only completed Todos) in this form of invocation:

return this.without.apply(this, this.active());

but not in this one:

return _.without(this.models, this.active());

In latter statement it returns array containing ALL models from collection.

Can't I use Underscore methods directly but only through Backbone's this context?

How to make 2nd statement work?

todos.js

var app = app || {};

var Todos = Backbone.Collection.extend({
  model: app.Todo,
  active: function() {
    return this.filter(function(todo) {
      return todo.get('completed') === false;
    });
  },
  completed: function() {
    return this.without.apply(this, this.active());
    // return _.without(this.models, this.active()); <--- Problem is here
  }
});

app.Todos = new Todos();

ADDED LATER:

Since _.without method does not accept array as a second parameter _.difference is more suitable for my task.

return _.difference(this.models, this.active());

Solution

  • The problem is that you use Undersore's without method improperly. It expects scalar value for 2nd parameter, whereas you pass array.

    Actually you don't need _.without at all.

    Don't try to reuse your active method in completed method. This is a bad practice. completed method has to be implemented by the same approach as active.

    So the code should look like this:

    var Todos = Backbone.Collection.extend({
      model: app.Todo,
      active: function() {
        return this.filter(function(todo) {
          return todo.get('completed') === false;
        });
      },
      completed: function() {
        return this.filter(function(todo) {
          return todo.get('completed') === true;
        });
      }
    });
    

    UPDATE:

    Q: So why the first invocation (which uses apply) works?

    A: Because apply method converts this.active() result, which is array, to list of values, which is exactly expected by _.without method. So this invocation works unlike the second one which is not equivalent to the first.

    However, as mentioned above, such type of code reusing is strongly unrecommended since it obscures the code logic, apart from the double array processing overhead.