JavaScript中for循环和for-in循环的区别

4
我发现在JavaScript中,for循环和for-in循环有所不同。
当我定义一个新的数组时:
var a=new Array();

然后我向其中放入一些值,但并非连续的,例如:

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。有人能告诉我为什么吗?

是的,它们用于不同的目的。此外,您有一些问题,您忘记了“var”,您应该使用“[]”而不是“new Array”,JS中的稀疏数组不是良好的做法。 - elclanrs
JavaScript数组是类似于列表的对象,而不是您通常使用的数组。 - PM 77-1
可能是JavaScript for...in vs for的重复问题。 - JLRishe
10个回答

3

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到小于数组长度”的计数不会产生预期的结果。在您的示例中,它接近工作,因为您手动创建的键恰好是0、1和4,几乎是顺序的。

如果您想要具有非连续键的数组--“非连续”如0、1、4等--您应该使用对象,而不是数组,例如:

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

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

2

for循环在从0到5的范围内迭代,直到i达到5。因此,i的取值为0、1、2、3、4和5,并且全部迭代。但是,使用for...in循环仅迭代它们的属性而不是0到5,而是你定义的0、1、4。

来自MDN

注意:不应该使用for...in来迭代重要的索引顺序的数组。

数组索引只是具有整数名称的可枚举属性,与一般对象属性相同。无法保证for...in将以任何特定顺序返回索引,并且将返回所有可枚举属性,包括那些具有非整数名称和那些被继承的属性。

由于迭代的顺序依赖于实现方式,因此在迭代重要访问顺序的数组时最好使用具有数字索引的for循环(或Array.forEach或for...of循环)。


0

我使用for-in循环是因为它是一种更短的形式,但有时您可能想要控制迭代变量。例如,如果您想要迭代偶数索引,您需要使用普通的for循环:

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

同样的道理,例如,如果您想要反向迭代:
for (var i = myarray.length-1; i >= 0; i--) {...}

当涉及对象时,for-in循环允许您将属性名作为迭代变量获取。例如:
 var obj = {year: 2014, city: "Surat"}
 for (var propn in obj) alert(propn + " = " + obj[propn]);

在你的例子中,我会使用for-in循环,因为你正在进行简单的迭代。此外,在非优化的Javascript编译器/解释器中,for-in循环甚至可能更快,因为变量增量是内部完成的。

0

首先,在 JavaScript 中,数组只能具有有序的数字索引,因此在数组上使用 for in 循环是没有意义的。因此,您可以在范围为 0array.length - 1 的任何索引处访问数组。但是,如果您想要使用 for in 循环来迭代数组,您当然可以这样做,但是常规的 for 循环更加适合。

当您没有有序数字索引时,可以使用 for in 循环。JavaScript 对象实际上是一个有序的哈希表。您可以使用 in 运算符访问 JavaScript 对象的键,该运算符返回对象的键,并通过访问该键的对象来获取值。

例如:

var obj = {
   hello: "world",
   world: "hello"
};

一个普通的for循环不起作用,所以你需要使用for in循环。
for(var i in obj) console.log(obj[i]);

对象也不返回足够准确的长度属性以遍历整个对象,因此for in循环是绝对必要的。

还要注意,通过将值分配给数组而不按照下一个空闲元素存在的顺序,将自动在跳过的元素中放置undefined

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

[0, 1, undefined × 2, 4]

0

在幕后,for-in循环只不过是一个for循环。 For(i in x)被分解为-

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

0

我已经阅读和听说普通的for循环:for(var i = 0; i < arr.length; i++)更快。但我会建议使用for of

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 方法。

0

for-in循环枚举变量的可枚举属性。对于您的数组,“0”、“1”和“4”被添加为数组的可枚举属性。因此,for-in循环只在“i”中获取0、1和4。

for循环使用i = 0到5。因此,您还尝试访问值2和3,这显然是未定义的。


0

语法

for (var k in obj)

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

因此,for-each 循环在处理对象时非常有用。但是,在循环数组时,最好使用常规的 for 循环。

这是一个在对象属性上使用 for-each 循环的示例:http://jsfiddle.net/nbtLpw0z/


0

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

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('---------------------');
Open console...

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('----------------------');
Open console...


0

你的“for”循环查看数组索引从0到4的所有值,因为这正是你要求它做的。所以它查看a[0]并找到一个值,然后是a[1](同样的情况),然后它转到a[2]并意识到你从未初始化a[2]的值,因此它是未定义的。a[3]也是如此,最后a[4]有一个值,所以它找到了它。

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

“for ... in ...”循环仅检查已初始化的值。你的数组有3个已初始化的值,因此它会检查这些值。它将按其索引顺序向你显示它们,但索引实际上不影响它正在查看的内容。因此,如果你将“a [1]”更改为“a [3]”,将“a [4]”更改为“a [10]”,则在使用“for ... in ...”循环时仍将获得完全相同的答案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接