Javascript 迭代JS数组的已定义元素

Javascript 迭代JS数组的已定义元素,javascript,jquery,Javascript,Jquery,我使用JS数组将ID映射到实际元素,即键值存储。我想迭代所有元素。我尝试了几种方法,但都有它的警告: for (var item in map) {...} 不会迭代数组的所有属性,因此它还将包括array.prototype的函数和扩展。例如,将来有人加入原型库,会中断现有代码 var length = map.lenth; for (var i = 0; i < length; i++) { var item = map[i]; ... } 它们迭代整个索引范围0..max

我使用JS数组将ID映射到实际元素,即键值存储。我想迭代所有元素。我尝试了几种方法,但都有它的警告:

for (var item in map) {...}
不会迭代数组的所有属性,因此它还将包括array.prototype的函数和扩展。例如,将来有人加入原型库,会中断现有代码

var length = map.lenth;
for (var i = 0; i < length; i++) {
  var item = map[i];
  ...
}
它们迭代整个索引范围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中都能工作的方式)?

没有。唯一的方法是完全忽略集合中的项,您提出的任何解决方案都必须对每个元素的值进行测试


您可以想出不同的方法将项键/值添加到对象文字或您拥有的其他内容中,但如果您不希望枚举未定义的项,则仍需要省略这些项。

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

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

有三个问题:

  • 您的需求使用了错误的数据类型
  • 您没有正确地在中为…使用
  • 如果您想拥有类似哈希表的内容,请使用普通的:

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

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

    但即使这样,您也应该打电话到(每次在
    中为…使用
    ):

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

    中使用以。。。在
    中,确保不包括原型添加:

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

    如果不检查值是否未定义,然后执行操作a或操作b,则无法执行很多操作。最好使用谓词来确定值是否未定义:

    x = $.grep(x, function(v, i) { return (typeof(v) != "undefined"); });
    
    1) 使用已经建议过的对象,这是迄今为止最好的解决方案

    2) 如果出于某种原因需要使用数组,请不要害怕使用

    for(var i, len = arr.length;len < i;i++)
    
    for(变量i,len=arr.length;len
    非常非常快


    3) 不要使用
    $。如果您想要性能,每个
    或类似的方法都会为每次迭代创建一个新的调用堆栈,这是一个巨大的开销

    使用EcmaScript 5内置,在非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;
    };
    

    正确的数字顺序在你的代码中是一个问题吗?不,这是一个无序的映射,我不关心顺序。我唯一关心的是迭代已定义的元素和已定义的元素。相关讨论使用对象是什么意思?使用对象作为映射进行查找:var map={};map[id]=true;if(map[id]){…}-1if(map[id]}不应使用,因为它将查找原型。一个“对象”和一个“数组”javascript也是一样。@sibidiba:不是。数组是一个对象,但对象不是数组。在JS中,数组是一个具有连续索引的数字数组,而对象更像是一个关联数组或映射。数组是通过
    []
    定义的,而对象是通过
    {}定义的
    。它们不一样。使用
    var x={};
    而不是
    var x=[];
    运行上一个示例,您将看到差异。这正是我正在做的。没有差异。for(映射中的var键)也将返回对象的/数组的成员函数。@sibidiba:这有一点不同。在@Yads的回答中使用的对象文字不应该影响其原型,因此,
    for/in
    将起作用。如果您遇到成员函数,则可能是因为您使用的代码扩展了
    object.proto键入
    ,这是一个非常糟糕的主意。因为不关心数字顺序,所以使用对象文字而不是数组文字。@patrick dw:但这就是sibidiba所指的。如果我没有错的话,可能会有人添加原型库,它扩展了
    对象。原型
    。@Felix Kling:不,prototypejs不扩展
    对象。prototype
    。它们仅使用
    对象
    命名空间来保存实用程序。需要将正在操作的对象作为第一个参数传递。“因为扩充Object.prototype(即,向对象添加实例方法)是危险的和侵入性的,所以所有这些方法都是静态方法,将对象作为其第一个参数。”@patrick dw:啊,好吧,我不知道(可能是他们过去扩展了它?)。无论如何,如果您的代码在您无法控制的环境中使用,您必须使用
    hasOwnProperty
    imo.Awesome。只想补充一点,hasOwnProperty在IE7中不起作用,但我只是停下来关心一个名为IE的东西。您可以使用以下一行代码保存一个级别:
    if(!map.hasOwnProperty(item))继续
    实际上是
    中的每一个……都被弃用了,而不是
    中的每一个……都被弃用了@Ian:我在哪里说过
    中的每一个……都被弃用了?
    x = $.grep(x, function(v, i) { return (typeof(v) != "undefined"); });
    
    for(var i, len = arr.length;len < i;i++)
    
    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;
    };