js中的遍历方法比较:map、for...in、for...of、reduce和forEach的特点与适用场景

简介: js中的遍历方法比较:map、for...in、for...of、reduce和forEach的特点与适用场景

map 方法

概述

map 方法是 JavaScript 数组提供的高阶函数之一,它接受一个函数作为参数,并对数组中的每个元素执行该函数。通过这种方式,开发者可以轻松地对数组元素进行转换或生成新的数组,而不需要编写显式的循环。

用法

使用 map 方法的关键是理解传递给它的函数。这个函数通常称为映射函数,它定义了对数组中每个元素的操作或转换。映射函数接受三个参数:当前正在处理的元素、当前元素的索引和操作的原始数组。

具体使用 map 方法的步骤如下:

定义映射函数,可使用匿名函数或命名函数。
调用数组的 map 方法,将映射函数作为参数传入。

例如,我们想将数组中的每个元素都加倍,可以定义以下映射函数:

function double(element) {
  return element * 2;
}
• 3

然后,我们可以使用 map 方法将映射函数应用于数组:

const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = numbers.map(double);

这个小例子中,map 方法会对 numbers 数组中的每个元素调用映射函数 double,并将返回值组成一个新的数组 doubledNumbers。

返回值特点

map 方法的返回值特点在于它返回一个全新的数组,而不会改变原始数组。这意味着原始数组保持不变,而生成的新数组包含经过映射函数处理后的元素。因此,map 方法是一种纯函数,不会对原始数据进行修改。

此外,由于 map 方法返回的是一个新数组,我们可以链式调用其他数组方法,如 filter、reduce 等,以进一步处理数据。这种方法的组合和链式调用能够提高代码的可读性和维护性。

需要注意的是,map 方法只会遍历已存在的数组元素,而不会执行已删除或未赋值的项。如果数组中的元素被修改或删除,在执行映射函数时会影响到 map 方法的结果。


for…in 循环

概述

for…in 循环是一种遍历对象属性的迭代循环,它通常用于遍历普通对象或数组等可迭代的结构。与传统的 for 循环或 forEach 方法不同,for…in 循环主要用于迭代对象的键(属性名),而非数组的索引或元素值。它提供了一种简洁且易于使用的方式来访问对象的属性。

用法

使用 for…in 循环的关键是理解其基本语法和用法。for…in 循环语法如下:

for (variable in object) {
   // 在此处执行操作
}

其中,variable 是一个变量,代表当前循环迭代的属性名;object 是要迭代的对象。

接下来,我们通过一个小例子来演示 for…in 循环的用法:

const person = {
  name: 'Alice',
  age: 30,
  gender: 'female'
};
for (let key in person) {
  console.log(key + ': ' + person[key]);
}

这个小例子中,我们定义了一个名为 person 的对象,然后使用 for…in 循环遍历 person 对象的属性。循环体内的语句 console.log(key + ': ' + person[key]) 输出了每个属性名和对应的属性值。

注意事项

在使用 for…in 循环时,有一些需要注意的事项:

  • 迭代顺序不确定:for…in 循环遍历对象属性时,并不能保证属性的迭代顺序。对象属性的遍历顺序可能因 JavaScript 引擎而异,因此不应依赖于属性的特定顺序。
  • 继承的属性也会被迭代:for…in 循环将遍历对象自身及其原型链上可枚举的属性。如果只希望遍历对象自身的属性,可以使用 object.hasOwnProperty(key) 来过滤继承的属性。
  • 不适用于数组遍历:虽然 for…in 循环可以遍历数组,但它并不是处理数组的最佳选择。由于数组的索引被视为对象的属性,遍历数组时可能会迭代到其他非数值属性。
  • 忽略 Symbol 属性:for…in 循环会忽略对象中的 Symbol 属性。如果需要遍历所有属性,包括 Symbol 属性,可使用 Object.getOwnPropertySymbols() 方法获取 Symbol 属性数组,并进行遍历。

for…of 循环

概述

for…of 循环是一种专门用于遍历可迭代对象的循环语法。与传统的 for 循环或 for…in 循环不同,for…of 循环主要用于访问数据结构中的元素值,而非索引或属性名。它提供了一种简单且易于使用的方式来迭代数组、字符串、Set、Map 等内置可迭代对象。

用法

使用 for…of 循环的关键是了解其基本语法和使用方法。for…of 循环语法如下:

for (variable of iterable) {
   // 在此处执行操作
}

其中,variable 是一个变量,代表当前循环迭代的元素值;iterable 是要迭代的可迭代对象。

接下来,我们通过一些小例子来演示 for…of 循环的用法:

  • 遍历数组:
const arr = [1, 2, 3, 4, 5];
for (let element of arr) {
  console.log(element);
}

我们定义了一个名为 arr 的数组,并使用 for…of 循环遍历数组的每个元素。循环体内的语句console.log(element) 输出了每个元素的值。

  • 遍历字符串:
const str = 'Hello';
for (let char of str) {
  console.log(char);
}

这个例子中,我们定义了一个名为 str 的字符串,并使用 for…of 循环遍历字符串的每个字符。循环体内的语句 console.log(char) 输出了每个字符。

  • 遍历 Set:
const set = new Set([1, 2, 3, 4, 5]);
for (let element of set) {
  console.log(element);
}

这个例子中,我们定义了一个名为 set 的 Set 对象,并使用 for…of 循环遍历 Set 中的每个元素。循环体内的语句 console.log(element) 输出了每个元素的值。

可迭代对象

for…of 循环可以遍历多种内置可迭代对象,包括但不限于:

数组(Array)

字符串(String)

类数组对象(如 arguments 对象)

Set

Map

Generator 对象

TypedArray

需要注意的是,for…of 循环不适用于普通对象(Plain Object),因为它们并非可迭代对象。

对于自定义对象,如果想要使用 for…of 循环进行迭代,需要实现 Iterable 接口,即定义一个 [Symbol.iterator] 方法,使其返回一个具有 next() 方法的迭代器对象。


forEach 方法

概述

forEach 方法是数组对象的一个内置方法,用于迭代数组中的每个元素。它接受一个回调函数作为参数,在遍历数组时会依次调用该函数,并传递当前元素、索引和原数组作为参数。与传统的 for 循环或 for…of 循环不同,forEach 方法主要用于遍历数组,并对每个元素执行特定操作。

用法

使用 forEach 方法的关键是了解其基本语法和使用方法。forEach 方法的语法如下:

array.forEach(function(element, index, array) {
   // 在此处执行操作
});

其中,array 是要遍历的数组;element 是回调函数中表示当前元素的参数;index 是回调函数中表示当前索引的参数;array 是回调函数中表示原数组的参数。

接下来,我们通过一些示例来演示 forEach 方法的用法:

  1. 遍历数组并输出每个元素:
const arr = [1, 2, 3, 4, 5];
arr.forEach(function(element) {
  console.log(element);
});

我们定义了一个名为 arr 的数组,并使用 forEach 方法遍历数组的每个元素。回调函数function(element) 输出了每个元素的值。

  1. 计算数组中每个元素的平方并存储到新数组中:
const arr = [1, 2, 3, 4, 5];
const squaredArr = [];
arr.forEach(function(element) {
  squaredArr.push(element * element);
});
console.log(squaredArr);

这个小例子中,我们定义了一个名为 arr 的数组,并使用 forEach 方法遍历数组的每个元素。在回调函数 function(element) 中,我们将每个元素的平方值推入 squaredArr 数组中,并最终打印 squaredArr

注意事项

在使用 forEach 方法时,需要注意以下几点:

  • 无法使用 break 或 continue 关键字:forEach 方法无法直接使用 break 或 continue 关键字来中断循环或跳过当前迭代。如果需要实现类似的功能,可以使用抛出异常或返回 false 来提前结束迭代。
  • 无法修改原数组:forEach 方法不会返回一个新的数组,也无法修改原数组的长度或内容。如果需要修改原数组,可以使用索引访问或其他数组方法(如 map、filter、reduce 等)。
  • 不支持异步操作:forEach 方法是同步执行的,不支持处理异步操作。如果需要处理异步操作,可以使用其他适合的方法,如 for 循环、for…of 循环、Promise 或 async/await。

reduce()方法

概述

reduce 方法是 JavaScript 数组的一个高阶函数,用于将数组的所有元素聚合为单个结果。它使用一个累加器和一个回调函数来进行聚合操作。

用法

reduce 方法的基本语法如下:

array.reduce(callback, initialValue)
• 1

其中,array 是要操作的数组;callback 是用于聚合操作的回调函数;initialValue 是可选的初始值,用作第一次调用回调函数时的累加器的初始值。

回调函数 callback 接受四个参数:accumulator(累加器)、currentValue(当前值)、currentIndex(当前索引)和 array(原始数组)。回调函数会被依次应用于数组的每个元素,从左到右进行聚合操作。

下面通过举例来演示 reduce 方法的用法:

  1. 计算数组元素之和:
const arr = [1, 2, 3, 4, 5];
const sum = arr.reduce(function(accumulator, currentValue) {
  return accumulator + currentValue;
}, 0);
console.log(sum); // 输出:15

上面这个例子里,我们定义了一个名为 arr 的数组,并使用 reduce 方法计算数组所有元素的和。回调函数 function(accumulator, currentValue) 将累加器 accumulator 和当前值 currentValue 相加,并返回新的累加器的值。

  1. 查找数组中的最大值:
const arr = [7, 2, 9, 1, 5];
const max = arr.reduce(function(accumulator, currentValue) {
  return Math.max(accumulator, currentValue);
}, arr[0]);
console.log(max); // 输出:9

此例子中,我们定义了一个名为 arr 的数组,并使用 reduce 方法查找数组中的最大值。回调函数 function(accumulator, currentValue) 使用 Math.max 函数比较累加器 accumulator 和当前值 currentValue,并返回较大的值作为新的累加器的值。初始累加器的值设为 arr[0],即数组的第一个元素。

  1. 数组元素计数和分类:
const arr = ['apple', 'banana', 'apple', 'orange', 'banana'];
const result = arr.reduce(function(accumulator, currentValue) {
  if (!accumulator[currentValue]) {
    accumulator[currentValue] = 1;
  } else {
    accumulator[currentValue]++;
  }
  return accumulator;
}, {});
console.log(result);
// 输出:
// {
//   apple: 2,
//   banana: 2,
//   orange: 1
// }

我们定义了一个名为 arr 的数组,并使用 reduce 方法统计每个元素出现的次数,并将结果存储在一个对象中。回调函数 function(accumulator, currentValue) 判断累加器 accumulator 中是否已存在当前值 currentValue 的计数,如果不存在则初始化为 1,否则增加计数。初始累加器的值通过 {} 创建一个空对象。

注意事项

  • reduce 方法可以接受一个可选的初始值 initialValue,用作第一次调用回调函数时的累加器的初始值。如果未提供初始值,则第一次调用回调函数时,累加器的初始值将为数组的第一个元素。
  • reduce 方法返回的是聚合的最终结果,而不是数组。

对比与选择

接下来我们对遍历常用方法: for 循环for...of 循环forEach 方法map 方法for...in循环reduce 方法。下面对这些方法进行对比和选择:

  1. for 循环:for 循环是最基本的遍历数组的方法,它提供了最大的灵活性,可以执行各种操作。但是需要手动管理索引和循环终止条件,并且代码相对繁琐。
  2. for…of 循环:for…of 循环是 ES6 引入的新语法,用于遍历可迭代对象(包括数组)。它简洁明了,不需要管理索引,而且支持使用 break 和 continue 关键字。然而,无法在循环中修改原数组的元素。
  3. forEach 方法:forEach 方法是一个高阶函数,提供了一种简洁的方式来遍历数组并对每个元素执行操作。它具有良好的可读性和易用性,无需关心索引和循环终止条件,但无法使用 break 或 continue 关键字。此外,forEach 方法是同步执行的,不支持处理异步操作。
  4. map 方法:map 方法可用于遍历数组并返回一个新数组,其中每个元素都经过回调函数的处理。与 forEach 方法不同,map 方法返回一个新数组,不会修改原数组的内容。这在需要对每个元素进行转换或映射的情况下非常有用。
  5. reduce 方法:reduce 方法允许通过迭代将数组的所有元素聚合为一个值。它使用一个累加器和回调函数来执行指定的聚合操作。reduce 方法可用于计算总和、求平均值、查找最大/最小值等。与 forEach 方法不同,reduce 方法返回单个结果而不是数组。

一般来说:

  • 如果只需要遍历数组并处理每个元素,没有返回值的要求,可以使用 forEach 方法,简洁易读。
  • 如果需要在遍历过程中修改原数组的元素,可以使用 for 循环或 map 方法。
  • 如果需要对每个数组元素进行转换或映射,并返回一个新的数组,可以使用 map 方法。
  • 如果需要将数组的所有元素聚合为单个结果,可以使用 reduce 方法。
  • 如果需要同时管理索引和元素,或者需要使用 break 或 continue 关键字来控制循环流程,可以使用 for 循环或 for…of 循环。

关键问题——for…in循环

单独把for...in循环拿出来,是因为它比较特殊

for…in循环用于遍历对象的可枚举属性,而不是数组的元素。它会遍历对象的所有可枚举属性,包括从原型链继承而来的属性。因此,不建议将for…in循环用于遍历数组。

以下是for…in循环的特点和适用场景:

  • for...in循环会遍历对象的可枚举属性,包括字符串类型的键和符号类型的键。
  • 在遍历过程中,循环变量会依次取得对象的每个属性名。可以通过使用该属性名获取对象的属性值。
  • 循环变量可能不按照任何特定顺序遍历对象的属性。
  • for...in循环还会遍历对象从原型链上继承而来的属性,这可能会导致意外的问题。
  • 可以通过使用Object.hasOwnProperty方法来判断当前属性是否为对象自身的属性而非继承来的属性。

由于for…in循环的特性,通常建议在处理数组时使用其他的遍历方式(如for循环、for…of循环、forEach方法、map方法和reduce方法),而将for…in循环用于遍历对象的属性。

相关文章
|
29天前
|
JavaScript 前端开发 程序员
前端原生Js批量修改页面元素属性的2个方法
原生 Js 的 getElementsByClassName 和 querySelectorAll 都能获取批量的页面元素,但是它们之间有些细微的差别,稍不注意,就很容易弄错!
|
1月前
|
Web App开发 JavaScript 前端开发
如何确保 Math 对象的方法在不同的 JavaScript 环境中具有一致的精度?
【10月更文挑战第29天】通过遵循标准和最佳实践、采用固定精度计算、进行全面的测试与验证、避免隐式类型转换以及持续关注和更新等方法,可以在很大程度上确保Math对象的方法在不同的JavaScript环境中具有一致的精度,从而提高代码的可靠性和可移植性。
|
27天前
|
监控 JavaScript Java
Node.js中内存泄漏的检测方法
检测内存泄漏需要综合运用多种方法,并结合实际的应用场景和代码特点进行分析。及时发现和解决内存泄漏问题,可以提高应用的稳定性和性能,避免潜在的风险和故障。同时,不断学习和掌握内存管理的知识,也是有效预防内存泄漏的重要途径。
122 52
|
1月前
|
JavaScript 前端开发 索引
js中DOM的基础方法
【10月更文挑战第31天】这些DOM基础方法是操作网页文档结构和实现交互效果的重要工具,通过它们可以动态地改变页面的内容、样式和行为,为用户提供丰富的交互体验。
|
1月前
|
缓存 JavaScript UED
js中BOM中的方法
【10月更文挑战第31天】
|
1月前
|
存储
`map()`方法在什么场景下会比 `forEach()`方法更高效?
综上所述,当需要对数组元素进行复杂的转换并生成新数组、进行链式调用和函数式编程、处理元素之间存在明确映射关系的情况以及与其他数组方法结合使用时,`map()`方法比`forEach()`方法更高效,能够使代码更加简洁、清晰和易于维护。
57 32
|
13天前
纸屑飘落生日蛋糕场景js+css3动画特效
纸屑飘落生日蛋糕CSS3动画特效是一款js+css3制作的全屏纸屑飘落,生日蛋糕点亮庆祝动画特效。
32 3
|
28天前
|
缓存 JavaScript 前端开发
JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用
本文深入讲解了 JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用。
41 5
|
1月前
|
JavaScript 前端开发
js中的bind,call,apply方法的区别以及用法
JavaScript中,`bind`、`call`和`apply`均可改变函数的`this`指向并传递参数。其中,`bind`返回一个新函数,不立即执行;`call`和`apply`则立即执行,且`apply`的参数以数组形式传递。三者在改变`this`指向及传参上功能相似,但在执行时机和参数传递方式上有所区别。
26 1
|
1月前
|
JavaScript 前端开发
.js方法参数argument
【10月更文挑战第26天】`arguments` 对象为JavaScript函数提供了一种灵活处理参数的方式,能够满足各种不同的参数传递和处理需求,在实际开发中具有广泛的应用价值。
41 7