迭代数组的 7 种方法以及每种方法的适用场景
访问数组和对象中的数据是 JavaScript 的重要组成部分,每个初学者都应该掌握。这里有一些常用的数组和对象迭代方法,以及关于何时使用每种方法的最佳实践。
迭代:对集合中的每个元素执行一次一组语句的过程。
在编程时,一个常见的场景是需要对数组中的每个元素执行相同的代码。无需手动对集合中的每个元素运行代码,您可以使用内置的数组方法迭代集合。
方法forEach()
该forEach
方法创建于 ES5 中,用于在不构建for
循环的情况下迭代集合中的元素。它接受一个回调函数作为参数,并对数组中的每个元素执行一次该函数。使用该方法forEach
迭代数组的好处之一是它是一种非破坏性方法,这意味着它不会更改原始数组。
const menuItems = ['cobb salad', 'hummus dip', 'tomato soup', 'chicken sandwich', 'veggie wrap']
menuItems.forEach(item => console.log(`you ordered a ${item} today.`))
// you ordered a cobb salad today.
// you ordered a hummus dip today.
// you ordered a chicken soup today.
// you ordered a chicken sandwich today.
// you ordered a veggie wrap today.
console.log(menuItems)
//['cobb salad', 'hummus dip', 'tomato soup', 'chicken sandwich', 'veggie wrap']
此方法没有返回值。如果您要创建一个包含输出的新数组,则需要创建一个空数组,并将新的输出推送到该数组。然而,这并不是创建新数组的最高效方法。如果您想返回一个新数组,可以使用本文中的其他方法。
const menuItems = ['cobb salad', 'hummus dip', 'tomato soup', 'chicken sandwich', 'veggie wrap']
const menuStatements = []
menuItems.forEach(item => menuStatements.push(`you ordered a ${item} today.`))
menuStatements
//["you ordered a cobb salad today., "you ordered a hummus dip today.", "you ordered a tomato soup today.", "you ordered a chicken sandwich today.", "you ordered a veggie wrap today."]
何时使用
该forEach
方法应谨慎使用。此方法的用例包括:在代码中记录错误,或者需要修改原始数组或对象。
&语句for...of
for...in
这些语句专门用于循环遍历数组和对象。它们与 非常相似,但forEach
有一个主要优点:在forEach
方法中,无论如何,它都会对集合中的每个元素运行回调函数。使用 和for...in
,for...of
您可以添加控制流(continue
、break
、return
、await
)。
for...in
for...in
可以循环遍历数组和对象,但最常用于对象。
const menu = {
appetizer: 'hummus dip',
entree: 'chicken sandwich',
dessert: 'cake'
}
for (const key in menu) {
console.log(`For your ${key}, we will be serving you a ${menu[key]}.`)
}
//For your appetizer, we will be serving you a hummus dip.
//For your entree, we will be serving you a chicken sandwich.
//For your dessert, we will be serving you a cake.
虽然for...in
可以循环遍历数组,但不建议这样做,因为它不会按索引顺序保存集合中的元素。这时for...of
循环就派上用场了。
for...of
该for...of
语句考虑了集合中元素的顺序。这对于数组非常有用,因为它可以保持输出按索引顺序排列。
const menuItems = ['cobb salad', 'hummus dip', '', 'tomato soup', 'chicken sandwich', 'veggie wrap']
for (const item of menuItems) {
if (item.length === 0) break
console.log(`you ordered a ${item} today.`)
}
//you ordered a cobb salad today.
//you ordered a hummus dip today.
//breaks after empty element
这些语句仍然不会像 那样创建一个包含结果的新数组forEach
。这两种方法都缺乏表现力,这意味着程序员需要更长的时间来阅读你的代码才能理解你的意图。
何时使用
使用for...in
循环快速从对象中提取属性并for...of
快速遍历数组中的元素,而无需使用结果创建新数组。
方法find()
find()
传入一个回调函数作为参数。该方法循环遍历数组中的每个元素,并将其传递给该函数。回调函数会一直运行,直到某个元素满足条件为止。
const orders = [
{appetizer: 'hummus dip', entree: 'avocado wrap', dessert: 'cake'},
{appetizer: 'salad', entree: 'chicken sandwich', dessert: 'ice cream'},
{appetizer: 'chips', entree: 'chicken sandwich', dessert: 'cake'}
]
orders.find(order => order.dessert === 'cake')
//{appetizer: "hummus dip", entree: "avocado wrap", dessert: "cake"}
可以看到,数组中有两个对象满足条件,但只返回了一个。这是因为find
只要有一个元素满足条件,该方法就会返回。
何时使用
当你想使用复杂的回调函数循环遍历数组时使用find
。这种方法表达能力强,能让其他程序员理解你正在循环遍历数组,只查找一个符合条件的元素。
方法filter()
该filter
方法与 类似,find
但返回数组中所有符合条件的元素。此方法还返回一个包含所有符合条件元素的新数组。
const orders = [
{appetizer: 'hummus dip', entree: 'avocado wrap', dessert: 'cake'},
{appetizer: 'salad', entree: 'chicken sandwich', dessert: 'ice cream'},
{appetizer: 'chips', entree: 'chicken sandwich', dessert: 'cake'}
]
const cake = orders.filter(order => order.dessert === 'cake')
cake
//[{appetizer: "hummus dip", entree: "avocado wrap", dessert: "cake"}, {appetizer: 'chips', entree: 'chicken sandwich', dessert: 'cake'}]
何时使用
当您想使用复杂的回调函数循环遍历数组并返回所有符合条件的元素时,可以使用filter
此方法。您可以使用此方法从数组中过滤重复项或查找数组中所有相似的对象。此方法也具有良好的表达能力,可以让其他程序员知道查找一个包含所有符合条件元素的新数组。
方法map()
到目前为止,filter
和find
方法只是从数组中传回元素。map
转换数组内的元素并为值创建一个新数组。
const orders = [
{appetizer: 'hummus dip', entree: 'avocado wrap', dessert: 'cake'},
{appetizer: 'salad', entree: 'chicken sandwich', dessert: 'ice cream'},
{appetizer: 'chips', entree: 'chicken sandwich', dessert: 'cake'}
]
const drinks = orders.map( order => {
return Object.assign({}, order, {
drink: 'water'
});
});
drinks
//[
//{appetizer: 'hummus dip', entree: 'avocado wrap', dessert: 'cake', drink: 'water'},
//{appetizer: 'salad', entree: 'chicken sandwich', dessert: 'ice cream', drink: 'water'},
//{appetizer: 'chips', entree: 'chicken sandwich', dessert: 'cake', drink: 'water'}
//]
何时使用
map
当您想要以非破坏性的方式用新的键值对更新对象、重新格式化对象以及更改数组的值(例如将所有值乘以一个数字)时,可以使用该方法。此方法表达能力强,可以让其他程序员知道要查找包含转换后值的新数组。
方法reduce()
该reduce
方法也转换数组但将其简化为奇异值。
const orders = [
{appetizer: 'hummus dip', entree: ['avocado wrap','chicken soup'], dessert: 'cake'},
{appetizer: 'salad', entree: ['chicken sandwich', 'veggie wrap'], dessert: 'ice cream'},
{appetizer: 'chips', entree: ['chicken sandwich', 'burger'], dessert: 'cake'}
]
let allEntrees = orders.reduce(
(accumulator, currentValue) => [...accumulator, ...currentValue.entree],
[]
)
allEntrees
//["avocado wrap", "chicken soup", "chicken sandwich", "veggie wrap", "chicken sandwich", "burger"]
在这种情况下,我们能够将所有条目组合成一个数组。回调有两个必需参数。第一个是accumulator
参数。它是循环中先前返回值的累加值。上面,在第一次迭代中,累加器是一个空数组。
第二次迭代累加器的值是第一个对象的条目数组(['avocado wrap','chicken soup']
),依此类推。第二个参数是currentValue
。这是正在通过回调函数运行的数组中的当前元素。
何时使用
当你想将数组转换为单个值时使用reduce
。此方法非常适合连接数组、计算数组中的值之和、展平数组以及统计对象中值的实例数。