New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
_.bindAll + comparator causes breakage on function-based Backbone methods #375
Comments
Can you try with the edge repo dist/ versions as well as the |
I was using the |
Which ever you were using, so |
Tried all 3: compat, standard, and underscore. Here's the essence of the code. Sorry to post in CoffeeScript, it's what my source is written in. Can convert if it helps. class Data extends Backbone.Collection
# ### Constructors, destructors and comparators
initialize : ->
_.bindAll @
comparator: (datum) ->
return datum.prop |
Ya, converting would help. I can't read that. |
There you go. This repo is amazing btw...thanks for all of your excellent work. Hated to even pollute it with an issue! var Data = Backbone.Collection.extend({
initialize: function() {
_.bindAll(this);
},
comparator: function(datum) {
return datum.prop;
}
}); |
I ran it through the CoffeeScript compiler to get a better idea of what it's really doing var Data, _ref,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
Data = (function(_super) {
__extends(Data, _super);
function Data() {
_ref = Data.__super__.constructor.apply(this, arguments);
return _ref;
}
Data.prototype.initialize = function() {
return _.bindAll(this);
};
Data.prototype.comparator = function(datum) {
return datum.prop;
};
return Data;
})(Backbone.Collection); |
Thanks! Which version of Backbone are you using? I know the latest Underscore will error when you perform I can't see anything wrong with the generated output so I don't think the issue is with these bits. I know Lo-Dash and later versions of Underscore perform a stable sort (which is a good thing) but may be an issue though it's a stretch. |
Good catch - it appears that Underscore has eliminated the global "_.bindAll" feature (new docs say methodNames are required). I suspect that this change is going to require a lot of configuring as the global _.bindAll had become a standard (if poor) practice. Nonetheless, mystery solved, and I'll proceed with more selectively binding within the collection. Thanks! |
@brandoncarl Well that shouldn't cause an issue w/ Lo-Dash, as we don't throw the error. I suspect it may be changes with other api like |
That doesn't work. The problem appears to rear its head at this point in the Backbone source: sort: function(options) {
if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
options || (options = {});
if (_.isString(this.comparator) || this.comparator.length === 1) {
this.models = this.sortBy(this.comparator, this);
} else {
this.models.sort(_.bind(this.comparator, this));
}
if (!options.silent) this.trigger('sort', this, options);
return this;
} When using Underscore 1.4.3, // Beginning of this.comparator using Lo-dash, referred to as "bound" in DevTools
// References: lodash.underscore.js:681
function () {
// `Function#bind` spec
// http://es5.github.io/#x15.3.4.5 Are the bound functions stored as a wrapped form of the function perhaps, not triggering |
I know Underscore 1.4.4 broke their |
Just checked...definitely 1.4.3 |
I am fine with the solution being "don't use a global _.bindAll when functions may be impacted". Also happy to keep helping if you want to fully resolve. |
I'd like to figure this out ;) The |
Works on Firefox latest. When I add the |
Ahh ok now! This is a problem w/ native bind vs the fallback. So after the |
Adding that leaves it broken in both. |
Here's a fix for this. If Backbone.sort is changed from:
to
things work fine. Basically, the Lo-dash bound function has implicit arguments (and thus function.length is 0), while the Underscore bound function retains explicit arguments (and thus function.length is, in my case, 1). Did that all make sense? |
This appears to be the case because Backbone's The sort function can be a string, take one, or two arguments. Since the Lo-dash binding doesn't set the "length" of the function (number of arguments), we run into errors. |
This is an issue with the assumed behavior of a bound function. Fallbacks and non-native alternatives do not set the |
Gotcha - so I think that leaves us with two things:
|
It is but generally no one attempts it because it's a bit hacky. You won't find it done in Underscore/ES5-Shim/MDN. It would require using |
Alright then...this is an easy fix for Backbone. I'll submit a pull request. |
@brandoncarl Cool! When submitting it to Backbone appeal to IE < 9, PhantomJS, & Safari 5 support as they may not budge for a Lo-Dash issue. They may just suggest not using |
@brandoncarl Ok so starting in v2.3.0 we will no longer be using native |
That's a great idea, and I like the added consistency as well. |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Got caught on this today...
If you extend a
Backbone.Collection
with acomparator
method and use_.bindAll
within the initialize function, it blows up the comparator. This does not happen when using Underscore.While I wasn't able to completely get down to the bottom of this, a key difference occurs in
Backbone.sort
, wherethis.comparator
no longer has a length of 1 (as it does in Underscore.Wish I could easily link to the Backbone source to help identify the discrepancy. Thought I'd identify it.
The text was updated successfully, but these errors were encountered: