for(数组中的i)和for(var i=0;i<array.length;i++)之间的差异

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

本文关键字:for length array i++ lt 之间 数组 var      更新时间:2023-09-26

这对javascript/jquery的所有人来说都是一个非常简单的问题。

在过去的两年里,我一直在编写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>');
}

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

但是,如果我用替换循环

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向我展示了数组中的以下元素。

https://i.stack.imgur.com/jw8Sy.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);
    }
};

它是在增加数组长度吗?

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

要么使用必要的保护措施,要么像第二个示例一样使用通用for,或者(如果可以信赖的话)使用Array#forEach

在这个SO回答和我的博客上有更多内容。


另外:确保您在某个地方声明了i(您似乎不在第一个示例中)。如果你不这样做,你就会成为隐式全球化的恐怖的牺牲品。


我已经在我的母版页中声明了原型。

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处有一个洞。

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

第一种方法将省略CCD_ 23。第二种方式将包括索引1(其中a[1]undefined)。

类似的情况可能发生如下:

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

就我个人而言,我怀疑(3)。

在第一个循环中执行console.log可能会揭示问题。

EDIT:从调试输出来看,(3)似乎是罪魁祸首。inArraypushIfNotExist所有数组上的键,因此第一个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
    }
}

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

简而言之,for ... in循环通过objectkeys进行迭代,而类似c的for循环通过数组索引进行迭代。JS不是强类型的,所以它允许您同时使用这两种方法,但数组的正确方法只有second或"forEach"方法。您可以在MDN上阅读更多信息。