关于数组:javascript中for循环和for-in循环之间的区别

difference between for loop and for-in loop in javascript

我发现在javascript中for循环和for in循环之间存在差异。

定义新数组时:

1
var a=new Array();

然后我将一些值放入,但不连续,例如:

1
a[0]=0;a[1]=1;a[4]=4;

当我使用for(i=0;i<5;i++)获取值并使用alert来显示时,它与使用for(i in a)不同。

前一个将显示索引2、3中显示"未定义"的元素,而for-in将只显示索引0、1和4。有人能告诉我为什么吗?


for (... in ...)通常用于迭代对象的属性(这是javascript用于关联数组的属性),而典型的for循环用于顺序数组。

在您的示例中,您实际上是使用键0、1和4创建关联数组。如果你想要一个真正的javascript数组,你可以使用a.push(0)a.push(1)等。以便按顺序将值添加到数组的末尾。

对于顺序数组,语法for (var i = 0; i < arr.length; i++)使i的计数从0到1小于数组的长度。这将允许i等于数组中的每个索引,一个接一个,允许您访问该数组中的每个元素。

但是,对于关联数组,键是非顺序的,因此使变量计数"从0到1小于数组长度"不会产生所需的结果。在您的示例中,它接近工作状态,因为您手工创建的键恰好是0、1和4,这几乎是连续的。

如果您想要一个具有非顺序键的数组--"非连续"如0、1、4等---

1
2
3
4
var obj = {};
obj[0] = 0;
obj[1] = 1;
obj[4] = 4;

然后使用for (... in ...)循环将是正确的语法。


for循环对它们进行迭代,直到i达到5,所以i=0,1,2,3,4,5,并对所有元素进行迭代。但是对于for…in循环,只迭代您定义的属性0到5,而不是0,1,4。

来自MDN:

Note: for..in should not be used to iterate over an Array where index order is important.

Array indexes are just enumerable properties with integer names and are otherwise identical to general Object properties. There is no guarantee that for...in will return the indexes in any particular order and it will return all enumerable properties, including those with non–integer names and those that are inherited.

Because the order of iteration is implementation dependent, iterating over an array may not visit elements in a consistent order. Therefore it is better to use a for loop with a numeric index (or Array.forEach or the for...of loop) when iterating over arrays where the order of access is important.


您的"for"循环查看数组索引的所有值(从0到4),这正是您要求它做的。因此,它查看一个[0]并找到一个值,然后找到一个[1](相同的交易),然后转到一个[2]并意识到您从未初始化一个[2]的值,因此它是未定义的。同样的情况也适用于[3],最后一个[4]有一个值,所以它会找到它。

这种类型的"for"循环将检查每个索引,无论是否定义。

A…for…在…"循环将只检查初始化的值。您的数组有3个已初始化的值,因此它会检查这些值。它将按照索引的顺序向您显示它们,但这些索引实际上并不影响它所看到的内容。所以如果你把你的"A[1]改为"A[3]",把"A[4]改为"A[10]",当你用"for…在……"循环"中。


我读过,也听说过,循环正常:for(var i = 0; i < arr.length; i++)更快。但我想说使用for of

1
2
3
4
var arr = [1,2,3], obj = {x: 1, y:2};
for(var value of arr) console.log(value) // 1, 2, 3
for(var key in obj) console.log(key) // x, y
for(var key of Object.keys(obj)) console.log(key) // x, y

可以使用Object.keys(obj)将对象的键转换为数组,并对其调用Array.prototype方法。


在引擎盖下,for-in循环只是for循环。因为(i in x)被分解为-

1
2
3
4
for(i=0;i<x.length;i++) {
if(x[i] != undefined)
console.log(x[i]);
}

对于遍历对象属性,建议使用for-each循环,而对于数组,建议使用for循环。在您的案例中,您可以使用push()获得相同的结果。

1
2
3
4
5
6
7
8
9
10
11
12
var a = []; //recommended way of declaring arrays over `new Arrays()`
a.push(0);
a.push(1);
a.push(4);
//usual for-loop
for (var i = 0; a.length > i; i++) //recommended
  console.log('a[', i, ']=', a[i]);
console.log('---------------------');
// for-each loop
for (var k in a) //not recommended
  console.log('a[', k, ']=', a[k]);
console.log('---------------------');
1
Open console...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var person = {
  'name': 'Adam'
};

for (var k in person)
  console.log('person.' + k, '=', person[k]);
console.log('----------------------');

person.age = 26; //new property

for (var k in person)
  console.log('person.' + k, '=', person[k]);
console.log('----------------------');

person['gender'] = 'Male'; //again a new property

for (var k in person)
  console.log('person.' + k, '=', person[k]);
console.log('----------------------');

person.name = 'Will'; //updating property

for (var k in person)
  console.log('person.' + k, '=', person[k]);
console.log('----------------------');
1
Open console...


对于初学者来说,没有必要在数组上使用for in循环,因为javascript中的数组只能有有序的数字索引。因此,您可以在0array.length - 1范围内的任何索引处访问数组。唉,如果您想使用for-in循环来迭代数组,那么当然可以使用正则for循环来进行迭代,但是,更适合使用正则for循环。

如果没有顺序数字索引,则使用for in循环。javascript对象实际上是一个有序的哈希表。您可以使用返回对象密钥的in运算符访问javascript对象的密钥,通过访问该密钥处的对象,可以获取值。

例如:

1
2
3
4
var obj = {
   hello:"world",
   world:"hello"
};

常规for循环不起作用,因此不需要使用for in循环。

4

对象也不会返回足够精确的长度属性来遍历整个对象,因此绝对需要一个for in循环。

还要注意,如果不按下一个自由元素的存在顺序给数组赋值,则会自动将undefined放在跳过的元素中。

在您的示例中,数组如下所示:

1
[0, 1, undefined × 2, 4]

我之所以使用in循环,是因为它的形式较短,但有时您可能希望控制迭代变量。例如,如果要在偶数索引上迭代,则需要使用normal for循环:

1
for (var i = 0; i < myarray.length; i+=1) {...}

例如,如果要向后迭代,则同样适用:

1
for (var i = myarray.length-1; i >= 0; i--) {...}

当然,对于对象,for-in循环允许您在迭代变量中获取属性名。

1
2
 var obj = {year: 2014, city:"Surat"}
 for (var propn in obj) alert(propn +" =" + obj[propn]);

在您的示例中,我将在中使用,因为您正在执行一个简单的迭代。此外,我认为在非优化的JavaScript编译器/解释器中,for-in循环会更快,因为变量增量是在内部完成的。


句法

for (var k in obj)

实际上是一个for each循环。它遍历对象的属性。您应该熟悉JavaScript对象。对象是键到值的映射。

因此,for each循环对于对象非常有用。但是,在数组中循环时,最好使用正则for循环。

下面是一个用于对象属性的for each循环的示例:http://jsfiddle.net/nbtlpw0z/。


for in循环枚举变量的可枚举属性。对于数组,"0"、"1"和"4"将作为可枚举属性添加到数组中。因此,对于in循环,在"i"中只得到0、1和4。

for循环在i=0到5之间工作。所以你试图访问2和3的值,这显然是未定义的。