Javascript 迭代JS数组的已定义元素
我使用JS数组将ID映射到实际元素,即键值存储。我想迭代所有元素。我尝试了几种方法,但都有它的警告: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
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;
};