Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

underscore.js filter function

I'm attempting to learn backbone.js and (by extension) underscore.js, and I'm having some difficulty understanding some of the conventions. While writing a simpel search filter, I thought that something like below would work:

var search_string = new RegExp(query, "i");

        var results = _.filter(this, function(data){
            return search_string.test(data.get("title"));
        }));

But, in fact, for this to work I need to change my filter function to the following:

var search_string = new RegExp(query, "i");

        var results = _(this.filter(function(data){
            return search_string.test(data.get("title"));
        }));

Basically, I want to understand why the second example works, while the first doesn't. Based on the documentation (http://documentcloud.github.com/underscore/#filter) I thought that the former would have worked. Or maybe this just reflects some old jQuery habits of mine... Can anyone explain this for me?

like image 521
bento Avatar asked Jun 23 '26 18:06

bento


1 Answers

I'd guess that you're using a browser with a native Array#filter implementation. Try these in your console and see what happens:

[].filter.call({ a: 'b' }, function(x) { console.log(x) });
[].filter.call([1, 2],     function(x) { console.log(x) });

The first one won't do anything, the second will produce 1 and 2 as output (http://jsfiddle.net/ambiguous/tkRQ3/). The problem isn't that data is empty, the problem is that the native Array#filter doesn't know what to do when applied to non-Array object.

All of Underscore's methods (including filter) use the native implementations if available:

Delegates to the native filter method, if it exists.

So the Array-ish Underscore methods generally won't work as _.m(collection, ...) unless you're using a browser that doesn't provide native implementations.

A Backbone collection is a wrapper for an array of models, the models array is in c.models so you'd want to:

_.filter(this.models, function(data) { ... });

Backbone collections have several Underscore methods mixed in:

Backbone proxies to Underscore.js to provide 28 iteration functions on Backbone.Collection.

and one of those is filter. These proxies apply the Underscore method to the collection's model array so c.filter(...) is the same as _.filter(c.models, ...).

This mixing-in is probably what's confusing the "should I use the native method" checks that Underscore is doing:

if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);

You can use _.filter on a plain old object (_.filter({a:'b'}, ...)) and get sensible results but it fails when you _.filter(backbone_collection, ...) because collections already have Underscore methods.

Here's a simple demo to hopefully clarify things: http://jsfiddle.net/ambiguous/FHd3Y/1/

like image 95
mu is too short Avatar answered Jun 26 '26 03:06

mu is too short



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!