开发者

Iterate over defined elements of a JS array

I'm using a JS array to Map IDs to actual elements, i.e. a key-value store. I would like to iterate over all elements. I tried several methods, but all have its caveats:

for (var item in map) {...}

Does iterates over all properties of the array, therefore it will include also functions and extensions to Array.prototype. For example someone dropping 开发者_StackOverflow中文版in the Prototype library in the future will brake existing code.

var length = map.lenth;
for (var i = 0; i < length; i++) {
  var item = map[i];
  ...
}

does work but just like

$.each(map, function(index, item) {...});

They iterate over the whole range of indexes 0..max(id) which has horrible drawbacks:

var x = [];
x[1]=1;
x[10]=10;
$.each(x, function(i,v) {console.log(i+": "+v);});

0: undefined
1: 1
2: undefined
3: undefined
4: undefined
5: undefined
6: undefined
7: undefined
8: undefined
9: undefined
10: 10

Of course my IDs wont resemble a continuous sequence either. Moreover there can be huge gaps between them so skipping undefined in the latter case is unacceptable for performance reasons. How is it possible to safely iterate over only the defined elements of an array (in a way that works in all browsers and IE)?


Use hasOwnProperty within for ... in to make sure that prototype additions aren't included:

for (var item in map)
  if (map.hasOwnProperty(item)) {
    // do something
  }


There are three issues:

  1. You should not use for...in to iterate arrays.
  2. You are using the wrong data type for your requirements.
  3. You are not using for...in correctly.

If you want to have something like a hash table then use a plain object:

var map = {};
map[123] = 'something';
map.foo = 'bar';
// same as map['foo'] = 'bar';
//...

It looks like an array, but it is not. It is an object with property 123. You can use either dot notation obj.key (only if the key is a valid identifier - 123 would not be valid so you have to use the following notation) or array notation obj['key'] to access object properties.

It seems that an object would be a more appropriate data structure.

But even then you should make a call to hasOwnProperty (every time you use for...in):

for(var key in obj) {
    if(obj.hasOwnProperty(key)) {
        //do something
    }
}

This checks whether a property is inherited from the prototype (it will return false then) or is truly an own property.


Use the EcmaScript 5 builtin Object.keys, and on non ES5 browsers, define it thus:

Object.keys = function (o) {
  var keys = [];
  var hasOwnProp = Object.prototype.hasOwnProperty;
  if (Object.prototype.toString.call(o) === '[object Array]') {
    for (var k in o) {
      if (+k === (k & 0x7fffffff) && hasOwnProp.call(o, k)) {
        keys[keys.length] = k;
      }
    }
    keys.sort(keys, function (a, b) { return a - b; });
  } else {
    for (var k in o) {
      if (hasOwnProp.call(o, k)) {
        keys[keys.length] = k;
      }
    }
  }
  return keys;
};


1) use an object like already suggested, it is by far the best solution.

2) if you for some reason need to use an array - don't be scared looping over it with

for(var i, len = arr.length;len < i;i++)

it's very very fast.

3) don't use $.each or similar methods if you want performance - they create a new callstack for every iteration, which is a huge overhead.


Don't use an array. Use an object hash instead

var map = {};
map[key] = value;
...
for (var key in map) {
   do something to map[key]
}


You can't do a lot without actually doing a check to see if the value is undefined and then doing operation a or operation b. It would be better to use a predicate to determine if the value is undefined:

x = $.grep(x, function(v, i) { return (typeof(v) != "undefined"); });


There isn't. The only way would be to omit the items from the collection completely, any solution you come up with would still have to do a test on each element for the value.

You could come up with different methods of adding the items key/value to object literals or what have you, but you would still need to omit undefined entries if you do not wish to enumerate over them.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜