迭代JS数组的已定义元素

时间:2011-01-12 17:22:24

标签: javascript jquery

我正在使用JS数组将ID映射到实际元素,即键值存储。我想迭代所有元素。我尝试了几种方法,但都有其注意事项:

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

迭代数组的所有属性,因此它还包括Array.prototype的函数和扩展。例如,将来有人投入Prototype库会制造现有代码。

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

确实有效,但就像

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

他们遍历整个范围的索引0..max(id),它们有着可怕的缺点:

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

当然,我的ID也不会像连续的序列。此外,它们之间可能存在巨大差距,因此在后一种情况下跳过未定义是出于性能原因而无法接受的。如何安全地迭代数组中定义的元素(以适用于所有浏览器和IE的方式)?

7 个答案:

答案 0 :(得分:4)

有三个问题:

  1. You should not use for...in to iterate arrays.
  2. 您使用了错误的数据类型以满足您的要求。
  3. 您没有正确使用for...in
  4. 如果你想要一个类似哈希表的东西,那么使用普通的object

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

    它看起来像一个数组,但事实并非如此。它是一个具有属性123的对象。您可以使用点表示法obj.key(仅当密钥是有效的标识符时 - 123无效,因此您必须使用以下表示法)或数组表示法obj['key']才能访问对象属性。

    似乎对象将是更合适的数据结构。

    但即便如此,您也应该拨打hasOwnProperty(每次使用for...in时):

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

    这将检查属性是否从原型继承(它将返回false)或真正属于自己的属性。

答案 1 :(得分:4)

for ... in中使用hasOwnProperty以确保不包含原型添加:

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

答案 2 :(得分:2)

1)使用已建议的对象,这是迄今为止最好的解决方案。

2)如果你出于某种原因需要使用一个数组 - 不要害怕用它循环

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

非常快。

3)如果你想要性能,不要使用$.each或类似的方法 - 它们为每次迭代创建一个新的callstack,这是一个巨大的开销。

答案 3 :(得分:2)

使用EcmaScript 5内置Object.keys,在非ES5浏览器上进行定义:

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;
};

答案 4 :(得分:0)

不要使用数组。请改用对象哈希

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

答案 5 :(得分:0)

如果没有实际检查以查看值是否未定义然后执行操作a或操作b,则无法做很多事情。最好使用谓词来确定值是否未定义:

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

答案 6 :(得分:-1)

没有。唯一的方法是完全省略集合中的项目,你提出的任何解决方案仍然需要对每个元素进行测试。

你可以想出不同的方法将项目键/值添加到对象文字或你有什么,但如果你不想枚举它们,你仍然需要省略未定义的条目。