【问题标题】:Differences between for and foreach in JavaScript 5JavaScript 5 中 for 和 foreach 的区别
【发布时间】:2016-10-02 21:07:20
【问题描述】:

我了解到for 会迭代数组的每个元素,即使不存在指定的情况,而forEach 会跳过不存在的情况。

此外,当写入for 时,必须指定一个计数器(我不是在说for...in),而forEach 只是使用函数迭代器。

嗯。请您回答以下四个问题好吗?

  1. forEach 真的会跳过不存在的数组的情况,而 for 不会吗?
  2. forEach 是否使用实习生计数器(我们不必编写它)?还是与for 完全不同的机制?
  3. 在某些语言中,forEach 不会按照与数组顺序相同的顺序遍历数组。 JavaScript 呢
  4. 最后,它们之间是否还有其他差异(当然,不包括语法/句法差异)?

【问题讨论】:

  • 阅读文档可以回答您的大部分问题。 forEach ... for

标签: javascript for-loop foreach


【解决方案1】:

for 关键字是一种语言结构,这是迭代事物的最快和最“原始”的方式。它有三种样式:

  1. C 风格 for: for ( initializer; condition; iterator ) { code... } - 这是最灵活且经过时间考验的版本。要遍历列表,您需要开始遍历从 0 到列表长度的所有列表索引。你也可以 遍历每隔一个,第三个等元素。大多数时候,这已经足够了。

  2. Javascript for-in for (var key in object) { code ... } - 这是遍历对象中每个键的好方法,例如,输出 JSON 对象的所有值。

  3. (ES2015) Javascript for-of: for (var item of collection) { code ... } - 这是新的,可在现代浏览器中使用。它使您可以跳过索引和计数器,并让您遍历集合的每个项目。 (例如,产品列表中的每个对象。)它与 C 样式的功能相同,但更易于使用。

但是,forEach 函数特定于 Javascript 中的 Array 对象,并允许您为数组中的每个项目运行一个函数。如果您有一个实用功能可以为您完成所有工作,那就太好了。

以下是如何使用上述所有类型的迭代:

// most plain kind of array with a length of 7
var myArray = [1, 2, 3, 4, 5, 6, undefined];
// a weird kind of array with no values between index 3 and 100
// its length is 102 
var mySparseArray = [1, 2, 3, 4];
mySparseArray[100] = 5;
mySparseArray[101] = 6;

// 1. C-style for
// ** can control how index is incremented
// ** needs an extra variable to iterate with
for (var i = 0; i < myArray.length; i += 1) {
    console.log(myArray[i]);
    // logs 1, 2, 3, 4, 5, 6, undefined
}

for (var i = 0; i < mySparseArray.length; i += 1) {
    console.log(myArray[i]); 
    // logs 1, 2, 3, 4, undefined, undefined, ... (up to index 100), 5, 6
} 

// 2. for..in
// ** keys are iterated over in non-guaranteed order
//    (you might get 2, "length", 1, 0, 3)
// ** all enumerable keys are included, that might include things other than indexes. 
for (var key in myArray) {
    console.log(myArray[key]);
    // logs 1, 2, 3, 4, 5, 6 
}

for (var key in mySparseArray) {
    console.log(mySparseArray[key]);
    // logs 1, 2, 3, 4, 5, 6
    // this for-loop "thinks" the array is an object with numbers for keys
}

// 3. for..of
// ** only available in browsers with ES2015 support
// ** supports many other things than Arrays - TypedArrays, Iterators...
for (var item of myArray) {
    console.log(item);
}

for (var item of mySparseArray) {
    console.log(item);
    // logs 1, 2, 3, 4, undefined, undefined, ... (up to index 100), 5, 6
}

// 4. forEach
// ** calls a function for each element (considered slow)
// ** supports only Arrays (unless you call it with Array.prototype.forEach.call)
function myCallback(element) {
  console.log(element);
}
myArray.forEach(myCallback); // logs 1, 2, 3, 4, 5, 6
mySparseArray.forEach(myCallback); // logs 1, 2, 3, 4, 5, 6

请务必在浏览器的开发者控制台中尝试这些!您可以看到上述每段代码的运行情况。

请务必查看the MDN reference on iterations.

【讨论】:

  • 关于跳过,OP 意味着不存在的属性,而不仅仅是具有undefined 值的属性。而.forEach 确实跳过了这些,尝试一个稀疏数组。
  • length 不应该是可枚举的,所以它不会被 for...in 迭代。
【解决方案2】:

所以,当您谈论 for 循环时,您的意思是实际的 for 循环,而不是 for...in(不应在数组上使用)。似乎有一点误解,让我开始吧:

for 循环不是用于遍历数组。并不是说您不应该这样做或者这很糟糕,但这不是它的主要功能-它实际上只是循环直到满足条件然后停止。最常见的语法恰好是for (var i =0; i &lt; max; i++),它恰好与数组循环匹配得很好,但这并不意味着你不能拥有for (var i = 100; Number.isInteger(i); i = i/2)。因此,话虽如此,以下是您问题的答案:

1。 forEach 会跳过数组中的缺失项吗?

回答:是的

forEach 是一个数组方法,与mapreduce 和其他方法一起确实跳过未分配的槽。这是为了帮助处理稀疏数组,例如

var arr = [];
arr[5] = "five";
arr[7] = "seven";
arr[10] = "ten";

console.log("---using forEach---");
arr.forEach(function(item) {
  console.log(item);
});

console.log("---using a for-loop---");
for (var i = 0; i < arr.length; i++) {
  console.log(arr[i]);
}

这是一个简单的示例,说明了您可能想要使用稀疏数组循环的原因 - 正如您所看到的,您的代码执行次数要少得多。这是一个稍微复杂一点的:

var arr = [];
arr[5] = "five";
arr[42] = "the answer";
arr[9001] = "over nine thousand";

arr.forEach(function(item) {
  console.log(item);
});

当您只有三个项目时,一个直接的 for 循环将执行(字面意思)超过九千次。

我必须在这里澄清一些事情 - unset 值是您尚未分配任何内容的任何指标。分配undefined 确实算作分配:

var arr = [];
arr[5] = "five";
arr[7] = undefined;
arr[10] = "ten";

arr.forEach(function(item) {
  console.log(item);
});

2。 forEach 是否使用内部计数器

答案:是的

您可以轻松获取当前结果,因为它已传递到回调中。

var arr = [];
arr[5] = "five";
arr[42] = "the answer";
arr[9001] = "over nine thousand";

arr.forEach(function(item, index) {
  console.log(index, "-", item);
});

3。 forEach按什么顺序进入

答案:从零开始,按升序排列

上面应该告诉你。这是另一个简单的例子:

var alphabet = ["a", "b", "c", "d", "e", "f", "g" ];

alphabet.forEach(function(letter, index) {
  console.log(index, letter);
})

4。 forforEach 之间的区别

答案:很难比较

两者之间的差异是我在开头提到的 - for 是 JavaScript 中的通用循环运算符 - 你可以使用它来遍历数组但您也可以将其用于各种其他目的。相比之下,forEach 专门绑定到数组。很难实际比较这两者,但如果我们仅限于谈论在数组上使用它们,这里有几点

for

  • + 您可以使用breakreturn 提前退出循环,因此您无需遍历整个数组
  • + 您可以控制数组遍历,因此您可以从末尾开始倒计时 (for (var i = arr.length; i &gt;= 0; i--)) 甚至返回或跳过项目(在循环体内执行 i--i += 2)李>
  • + 被广泛认为是一种循环机制,因为它被用于许多其他语言中
  • +/- 您将遍历整个数组长度,即使是稀疏数组也是如此。
  • - 即使您不关心循环计数器,您也必须维护它。

forEach

  • + 很好地处理稀疏数组
  • + 接受回调,因此您可以通过将函数传递给.forEach 调用来重用函数
  • + 上面的另一个好处是回调主体内所有内容的功能范围(尽管在 ES6 中 letconst 无关紧要)
  • + 惯用 JavaScript
  • +/- 您将只检查稀疏数组中的当前项目
  • - 不能提前退出,不过您可以使用find
  • - 您无法控制数组的遍历方式。

PS:荣誉奖转到for...of

感谢@Bergi,我记得我确实想在此处包含一些内容:

您没有提到但存在的一个循环是for...of loop,它在语法上与for...in 循环相似,但它旨在处理数组以及其他可迭代对象。它是一个相对较新的构造(至少比forEach 更新),因为它在 ES6 规范中,所以广泛的网络支持可能不存在,但它是上述两者的替代方案。使用起来非常简单:

var arr = [];
arr[5] = "five";
arr[7] = "seven";
arr[10] = "ten";

for (item of arr) {
  console.log(item);
}

因此,简而言之,它就像for 循环一样工作,因为它会遍历所有内容,但您不必声明和维护计数器。

【讨论】:

  • forEach 是否“很好”地处理稀疏数组是有争议的,许多人希望得到 undefined 值而不是跳过。
  • 我认为forfor…of.forEach 更惯用
  • @Bergi 关于稀疏数组,这可能取决于您希望如何处理它们。根据我的经验,大多数时候我只想要它们中存在的东西,尽管我会说这不是所有时间。我绝对可以看到循环遍历所有内容的用途。然而,似乎 JavaScript(或者 ECMAScript)已经采取了稀疏数组应该只包含其现有成员的立场。因此,“好”可能需要在那里进行限定,但对于某些用例来说,它是合适的。
  • @Bergi 和for,到处都是惯用语,(可能应该这样说,而不是“公认的”),但我不会认为它是 JS 特定的。 forEachmapreducefilterfind 等数组方法是更独特的 JavaScript。当然,它们存在于它之外,但是在谈论 JS 数组处理机制时,它们应该得到它们的位置,这确实使它们脱颖而出并得到广泛认可。
【解决方案3】:

vlaz 已经在 cmets 中回答了,我只想:

主要区别在于forEach调用可以按数组中的元素生成一个闭包,这在需要重用一些内部变量时非常有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-16
    • 1970-01-01
    • 2017-01-05
    • 2012-06-11
    • 1970-01-01
    • 2012-11-08
    • 2011-01-17
    相关资源
    最近更新 更多