关于javascript:for(i in array)和for(var i = 0; i< array.length; i ++)之间的差异

Difference between for(i in array) and for(var i=0;i<array.length;i++)

本问题已经有最佳答案,请猛点这里访问。

对于所有的javascript/jquery用户来说,这是一个非常简单的问题。

我在过去的两年中一直在编写JavaScript,今天我遇到了一个奇怪的问题。

我正在从我的C# Webmethod中取一个jsonarray,并由jQuery.ajax()呼叫它。

当我这样做的时候

1
2
3
4
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>');
}

附加的表增加了两行,将每个字段都设置为"未定义"。看到这个图像

但是,如果我用

1
2
3
4
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>');
}

未定义的行消失..看到图像

我为自己的愚蠢道歉,但我以前从未遇到过这样的问题。原因可能是什么??

编辑:

阵列非常好。而且里面没有洞。另一个观察是未定义的属性只出现在网格的底部。我认为它正在处理超过数组长度的两个额外索引。

编辑-2

我的console.log向我展示了数组中的以下元素。

网址:http://i.imgur.com/ri5tjdk.jpg

我已经在主页上声明了原型。

1
2
3
4
5
6
7
8
9
10
11
12
13
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);
    }
};

是增加数组长度吗????


javascript的for-in和c的foreach是完全不同的。除非使用适当的保护措施,否则不要使用for-in来遍历数组,这不是它的用途。它循环遍历对象的可枚举属性,而不是数组索引或条目。

要么使用必要的保护措施,要么像第二个例子一样使用通用的for,或者(如果您可以依靠它)使用Array#forEach

更多信息,请回答,并在我的博客上。

另外:一定要在某个地方声明i(你似乎不在第一个例子中)。如果你不这样做,你就成了暗含全球恐怖分子的牺牲品。

I've declared the prototypes in my Master page.

Array.prototype.inArray = function ...

这就是为什么您不使用for-in在没有安全保护的情况下循环通过阵列的原因。同样,请参见上面的链接。您的for-in循环将循环访问数组索引属性("0""1"等--是的,它们实际上是字符串),以及您添加到Array.prototype中的函数名(inArray等)。


这两个循环有几种不同的方式。

(1)第一个应该是for (var i in JSONRaw)。在window上设置i属性可能会产生不明显的后果。

(2)JSONRaw不是一个数组,而是一个恰好有一个定义错误的length属性的对象。

(3)在第一个循环中出现的JSONRaw上设置了其他属性。

(4)阵列可以有"孔"。例如,下面的数组在索引1处有一个孔。

1
2
3
var a = [];
a[0] = 0;
a[2] = 2;

第一种方法是省略1。第二种方法包括指数1(其中a[1])为undefined)。

类似情况可能发生如下:

1
2
var a = [0, 1];
a.length = 3;

我个人怀疑(3)。

在第一个循环中执行EDOCX1[11]可能会发现问题。

编辑:从您的调试输出来看,(3)似乎是罪魁祸首。inArraypushIfNotExist是所有数组上的键,因此第一个for循环迭代它们。

如果要使用第一个循环,则有三个选项:

(1)不要在Array.prototype上增加这些功能。通常不鼓励添加到内置原型中。

(2)使用Object.defineProperty(在IE8中不起作用):

1
2
3
4
5
6
7
8
9
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)检查是否在原型上定义了密钥。

1
2
3
4
5
for(var i in JSONRaw) {
    if(JSONRaw.hasOwnProperty(i)) {
        //do something
    }
}

尽管大多数人使用第二个循环只是因为潜在的缺陷(以及更快的性能)。


简言之,for ... in循环通过objectkeys迭代,而c-like for循环通过数组索引迭代。JS的类型不是很强,所以它允许您双向获取,但数组的正确方法只是second或'foreach'方法。您可以在MDN上阅读更多内容。