对于所有javascript / jquery家伙来说,这将是一个非常简单的问题。
我从过去2年开始编写javascript,今天我遇到了一个奇怪的问题。
我从C# Webmethod
获取JSON阵列并通过jQuery.ajax()
当我这样做时
for (i in JSONRaw) {
Index = Index + 1;
$('#bottomGridDashboard').append('<tr> <td>' + Index + '</td> <td>' + JSONRaw[i].DisplayName + '</td> <td>' + JSONRaw[i].SpeedInKPH + '</td> <td><img src="' + JSONRaw[i].ImageURL + '" height="20px" alt="" /></td> <td>' + JSONRaw[i].DepotID + '</td> <td>' + JSONRaw[i].RouteID + '/' + JSONRaw[i].ScheduleID + '/' + JSONRaw[i].TripID + '</td> <td>' + JSONRaw[i].Direction + '</td> <td>' + JSONRaw[i].LastStop + '</td> <td> ' + JSONRaw[i].ETAMinutes + ' </td> </tr>');
}
附加表增加了两行,将每个字段设置为“未定义”。 See this Image
但是,如果我用
替换循环for (var i = 0; i < JSONRaw.length;i++ ) {
Index = Index + 1;
$('#bottomGridDashboard').append('<tr> <td>' + Index + '</td> <td>' + JSONRaw[i].DisplayName + '</td> <td>' + JSONRaw[i].SpeedInKPH + '</td> <td><img src="' + JSONRaw[i].ImageURL + '" height="20px" alt="" /></td> <td>' + JSONRaw[i].DepotID + '</td> <td>' + JSONRaw[i].RouteID + '/' + JSONRaw[i].ScheduleID + '/' + JSONRaw[i].TripID + '</td> <td>' + JSONRaw[i].Direction + '</td> <td>' + JSONRaw[i].LastStop + '</td> <td> ' + JSONRaw[i].ETAMinutes + ' </td> </tr>');
}
未定义的行消失.. See the image
我为自己的愚蠢道歉,但我以前从未遇到任何此类问题。 可能是什么原因?
修改
阵列非常好。并且它没有漏洞。 另一个观察是未定义的属性仅出现在我的网格底部。我认为它正在处理两个额外的索引而不是数组长度。
修改-2
我的console.log向我展示了我的数组中的以下元素。
http://i.imgur.com/rI5TjdK.jpg
我已在主页面中声明原型。
Array.prototype.inArray = function (comparer) {
for (var i = 0; i < this.length; i++) {
if (comparer(this[i])) return true;
}
return false;
};
Array.prototype.pushIfNotExist = function (element, comparer) {
if (!this.inArray(comparer)) {
this.unshift(element);
}
};
是否增加了数组长度。 ? ?
答案 0 :(得分:7)
JavaScript的for-in
和C#的foreach
是完全不同的东西。除非使用适当的安全措施,否则不要使用for-in
循环遍历数组,这不是它的用途。它遍历对象的可枚举属性,而不是数组索引或条目。
要么使用必要的安全措施,要么像第二个例子那样使用通用for
,或者(如果可以依赖它)使用Array#forEach
。
this SO answer和on my blog中的更多内容。
另外:确保你在某个地方声明i
(你似乎不在你的第一个例子中)。如果你不这样做,你会成为The Horror of Implicit Globals的牺牲品。
我已在主页面中声明原型。
Array.prototype.inArray = function ...
这就是为什么在没有安全措施的情况下不使用for-in
来循环数组的原因。再次,请参阅上面的链接。您的for-in
循环将遍历数组索引属性("0"
,"1"
,依此类推 - 是的,它们确实是字符串)而也您添加到Array.prototype
(inArray
等)的功能名称。
答案 1 :(得分:4)
这两个循环有几种不同的方式。
(1)第一个应该是for (var i in JSONRaw)
。在i
上设置属性window
可能会产生不明显的后果。
(2)JSONRaw
不是数组,而是碰巧具有错误定义的length
属性的对象。
(3)JSONRaw
上设置的其他属性出现在第一个循环中。
(4)阵列可能有“洞”。例如,下面的数组在索引1
处有一个洞。
var a = [];
a[0] = 0;
a[2] = 2;
第一种方法会省略1
。第二种方式包括索引1
(a[1]
为undefined
)。
类似情况可能发生如下:
var a = [0, 1];
a.length = 3;
我个人怀疑(3)。
在第一个循环中执行console.log
可能会发现问题。
编辑:从您的调试输出中,似乎(3)是罪魁祸首。 inArray
和pushIfNotExist
是所有数组上的键,因此第一个for
循环遍历它们。
如果您打算使用第一个循环,您有三个选择:
(1)不要在Array.prototype
上添加这些功能。通常不鼓励添加内置原型。
(2)使用Object.defineProperty
(在IE8中不起作用):
Object.defineProperty(Array.prototype, 'inArray', {
enumerable: false, //this makes it not show up in the for loop
value: function (comparer) {
for (var i = 0; i < this.length; i++) {
if (comparer(this[i])) return true;
}
return false;
}
});
(3)检查原型上是否定义了键。
for(var i in JSONRaw) {
if(JSONRaw.hasOwnProperty(i)) {
//do something
}
}
虽然大多数人只是使用第二个循环,因为潜在的陷阱(和更快的性能)。
答案 2 :(得分:2)
简而言之,for ... in
周期遍历keys
object
,而c-like for
周期遍历数组索引。 JS没有那么强类型,因此它允许你获得两种方式,但是数组的正确方法只是第二种或'forEach'方法。您可以阅读更多on MDN。