I've been under the impression that only Array
objects have a .length
property. But, then again, I've also seen mentions of objects that are "array-like". I've not looked into this, and now it seems like my ignorance of this topic in JS may be biting me in the ass. Case in point:
I've got the following code:
var View = function(options) {
// code
};
_.extend(View, Backbone.Events, {
make_children: function(parent) {
// code
}
});
Later on, I use this View
Function
with Underscore's _.each
, which decides this function object is an array, because it has a .length
property:
// Code from Underscore.js's `_.each`:
} else if (obj.length === +obj.length) { // This is true
for (var i = 0, l = obj.length; i < l; i++) { // **So, execution goes here**
if (iterator.call(context, obj[i], i, obj) === breaker) return
}
} else {
for (var key in obj) {
if (_.has(obj, key)) { // **Execution does __not__ go here**
if (iterator.call(context, obj[key], key, obj) === breaker) return;
}
}
}
This results in code that doesn't work, because obj[i]
where i
is an integer index, is not actually defined on my obj
View
. To be precise, in the above code, obj[0]
is undefined
while obj.length === +obj.length
is true
and obj.length
is 1
. What's going on here?
Addendum
Underscore's chief maintainer says the following on https://github.com/documentcloud/underscore/pull/510:
Simply making each reject function objects doesn't really help. We've made a conscious decision to use a numerical length property to detect array-like objects.
Instead, don't pass function objects to
each
.
Addendum 2
Realized that since I couldn't pass a function object to _.each
, I could just "cast it" to a regular object like so:
var regular_obj = _.extend({}, View);