Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

each implementation in the underscore.js library

Tags:

javascript

Question about the implementation of the "each" function I found in the underscore.js source code (source below).

First, could someone explain what the line "else if (obj.length === +obj.length) " is checking for.

Second, could someone explain why hasOwnProperty.call(obj, key) is used, as opposed to obj.hasOwnProperty? Is it because the passed in obj may not implement hasOwnProperty (which I thought every javascript object did)

any insights appreciated. Thanks.

  // The cornerstone, an `each` implementation, aka `forEach`.
  // Handles objects with the built-in `forEach`, arrays, and raw objects.
  // Delegates to **ECMAScript 5**'s native `forEach` if available.

  var each = _.each = _.forEach = function(obj, iterator, context) {

    if (obj == null) return;
    if (nativeForEach && obj.forEach === nativeForEach) {
      obj.forEach(iterator, context);
    } else if (obj.length === +obj.length) {
      for (var i = 0, l = obj.length; i < l; i++) {
        if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;

      }
    } else {
      for (var key in obj) {
        if (hasOwnProperty.call(obj, key)) {
          if (iterator.call(context, obj[key], key, obj) === breaker) return;
        }
      }
    }
  };
like image 971
user772110 Avatar asked Aug 01 '11 00:08

user772110


1 Answers

This:

+obj.length

...will do a toNumber conversion on the value of length.

It appears as though they're making sure that length references a number by doing the toNumber conversion, and verifying that it's still the same number after the conversion.

If so, they assume that it is an Array, or at least an Array-like object for iteration.

If not, they assume that enumeration of all key value pairs is desired.

var obj = {
     length:null,
     someprop:'some value'
};

obj.length === +obj.length; // false, so do the enumeration
var obj = {
    length: 2,
    "0":'some value',
    "1":'some other value'
};

obj.length === +obj.length;  // true, not an actual Array, 
                             //     but iteration is still probably wanted

Of course you could have an object with a length property that is a primitive number, but still intend to enumerate the properties.

var obj = {
    length: 2,
    "prop1":'some value',
    "prop2":'some other value'
};

obj.length === +obj.length;  // true, it will iterate, but it would
                             //           seem that enumeration is intended
like image 190
user113716 Avatar answered Oct 04 '22 20:10

user113716