javascript进阶知识6-数组的迭代遍历

295 阅读6分钟

上一章我们了解了数组的创建、增删查改,本节我介绍介绍数组的各种迭代遍历吧!

1.遍历

以前我们遍历数组都是用for(let i =0;i<arr.length;i++)进行遍历的,但是在JS里数组有了几个新的遍历数组的方法。他们是forEach()for...of...for...in...

forEach()相当于使用for循环遍历数组,该方法接收3个参数:元素、索引、数组本身。其中元素是数组中当前搜索的元素,索引是当前元素的索引,而数组就是正在搜索的数组。

let numbers = [1, 2, 3];
numbers.forEach((item, index, array) => {
    console.log('item', item, 'index', index, 'array', array);
})

// item 1 index 0 array [ 1, 2, 3 ]
   item 2 index 1 array [ 1, 2, 3 ]
   item 3 index 2 array [ 1, 2, 3 ]

for...in...是一种严格的迭代语句,用于枚举对象中的非符号键属性。在数组中也就是得到每一个元素的索引。

let numbers = [1, 2, 3];
for (const index in numbers) {
    console.log('index', index, 'item', numbers[index]);
}

//  index 0 item 1
    index 1 item 2
    index 2 item 3

for...of...对一种严格的迭代语句,用于可遍历对象的元素。在数组中也就是得到每一个元素的值。

let numbers = [1, 2, 3];
for (const item of numbers) {
    console.log('item', item);
}

// item 1
   item 2
   item 3

除此之外,在ES6中,Array的原型上暴露了3个用于检索数组内容的方法:keys()values()entries()。但是数组的这3个方法都返回的是迭代器,所以我们需要将他们通过Array.from()转为数组实例。

const a = ['foo', 'bar', 'baz', 'qux'];
const keys = Array.from(a.keys())
const values = Array.from(a.values());
const aEntries = Array.from(a.entries());

console.log(keys);  //[ 0, 1, 2, 3 ]
console.log(values);  //[ 'foo', 'bar', 'baz', 'qux' ]
console.log(aEntries);  //[ [ 0, 'foo' ], [ 1, 'bar' ], [ 2, 'baz' ], [ 3, 'qux' ] ]

可以发现keys()返回的是数组索引的迭代器,values()返回的是数组元素的迭代器,entries()返回的是索引/值对的迭代器。(是不是感觉和for..in..for..of..很类似呀)

entries()配合for..of..效果更好哦~

const a = ['foo', 'bar', 'baz', 'qux'];
for (const [idx, element] of a.entries()) {
    console.log('idx', idx, 'element', element);
}

//    idx 0 element foo
      idx 1 element bar
      idx 2 element baz
      idx 3 element qux

2.数组的迭代方法

数组的迭代方法主要有every()、some()、map()、filter()、forEach()、reduce()、reduceRight(),除了reduce()、reduceRight()外其他的5个方法都接收两个参数,以每一项为参数运行的函数,以及可选的作为函数运行上下文的作用域对象(影响函数的this值)。传给每个方法的函数都接收3个参数:数组元素、元素索引和数组本身。(forEach之前说了,就不再说了)

(1)every()

对数组的每一项都运行传入的函数,如果每一项函数都返回true,则这个方法返回true。

let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1]
let result = arr.every((item, index, array) => item > 2)
console.log(result); //false

等价于
let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1]
let result = arr.every(function(item, index, array) {
    if (item > 2) {
        return true
    } else return false
})
console.log(result); //false

(2)some()

对数组中每一项都运行传入的函数,如果有一项函数返回true,则这个方法返回true。

let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1]
let result = arr.some((item, index, array) => item > 2)
console.log(result); //true

等价于
let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1]
let result = arr.some(function(item, index, array) {
    if (item > 2) {
        return true
    } else return false
})
console.log(result); //true

可以发现every()和some()是很相似的,都是从数组中搜索符合某个条件的元素。但是every()要传入的函数必须对每一项都返回true,他才会返回true;否则,他就是返回false。而对some()而言,只要有一项让传入的函数返回true,他就会返回true。

(3)filter()

对数组每一项都运行传入的函数,函数返回true的项会组成新数组后返回。这个方法非常适合从数组中筛选满足给定条件的元素。

let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1]
let result = arr.filter((item, index, array) => item > 2)
console.log(result); // [ 3, 4, 5, 4, 3 ]

这个方法基于给定的函数来决定某一项是否应该包含在它返回的数组中。上述例子就是返回一个所有数值都大于2的数组。

(4)map()

对数组的每一项都运行传入的函数,返回由每次函数调用的结果构成的数组。这个方法非常适合创建一个与原始数组元素一一对应的新数组。

let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1]
let result = arr.map((item, index, array) => item * 2)
console.log(result); // [2, 4, 6, 8, 10,8, 6, 4, 2]

(5)reduce()与reduceRight()

reduce()reduceRight()的作用是归并,他们会迭代数组的所有项,并在此基础上构建一个最终返回值。reduce()方法从数组第一项开始遍历到最后一项,reduceRight()从最后一项开始遍历至第一项。

他们也都接收两个参数:第一个参数是对每一项都会运行的函数,第二个参数是可选的以之为归并起点的起始值。传给reduce()reduceRight()的函数都可接收4个参数:上一个归并值、当前项、当前项的索引和数组本身。这个函数返回的任何值都会成为下一次调用这个函数的第一个参数(归并值)。

let arr = [1, 2, 3, 4, 5]
let result = arr.reduce(function(pre, cur, index, array) {
    console.log('pre:', pre, 'cur:', cur, 'index:', index, 'array:', array);
    return 99;
}, 0)

pre: 0  cur: 1 index: 0 array: [ 1, 2, 3, 4, 5 ]
pre: 99 cur: 2 index: 1 array: [ 1, 2, 3, 4, 5 ]
pre: 99 cur: 3 index: 2 array: [ 1, 2, 3, 4, 5 ]
pre: 99 cur: 4 index: 3 array: [ 1, 2, 3, 4, 5 ]
pre: 99 cur: 5 index: 4 array: [ 1, 2, 3, 4, 5 ]

如果没有给这两个方法传入第二个参数,则第一次迭代将从数组的第二项开始,因此传给归并函数的第一个参数就是数组的第一项,第二个参数就是数组的第二项。

let arr = [1, 2, 3, 4, 5]
let result = arr.reduce(function(pre, cur, index, array) {
    console.log('pre:', pre, 'cur:', cur, 'index:', index, 'array:', array);
    return 99;
})

pre: 1  cur: 2 index: 1 array: [ 1, 2, 3, 4, 5 ]
pre: 99 cur: 3 index: 2 array: [ 1, 2, 3, 4, 5 ]
pre: 99 cur: 4 index: 3 array: [ 1, 2, 3, 4, 5 ]
pre: 99 cur: 5 index: 4 array: [ 1, 2, 3, 4, 5 ]

使用reduce()方法,很方便于执行累加操作或者统计操作

累加:(求数组各元素的总数)
let arr = [1, 2, 3, 4, 5]
let sum = arr.reduce(function(sum, cur, index, array) {
    console.log('sum:', sum, 'cur:', cur, 'index:', index, 'array:', array);
    return cur + sum;
})
console.log('sum', sum);

sum: 1  cur: 2 index: 1 array: [ 1, 2, 3, 4, 5 ]
sum: 3  cur: 3 index: 2 array: [ 1, 2, 3, 4, 5 ]
sum: 6  cur: 4 index: 3 array: [ 1, 2, 3, 4, 5 ]
sum: 10 cur: 5 index: 4 array: [ 1, 2, 3, 4, 5 ]
sum 15


统计:(统计数组中1的个数)
let arr = [1, 2, 3, 1, 1]
let total = arr.reduce(function(total, cur, index, array) {
    console.log('total:', total, 'cur:', cur, 'index:', index, 'array:', array);
    total += cur == 1 ? 1 : 0
    return total;
}, 0)
console.log('total', total);

total: 0 cur: 1 index: 0 array: [ 1, 2, 3, 1, 1 ]
total: 1 cur: 2 index: 1 array: [ 1, 2, 3, 1, 1 ]
total: 1 cur: 3 index: 2 array: [ 1, 2, 3, 1, 1 ]
total: 1 cur: 1 index: 3 array: [ 1, 2, 3, 1, 1 ]
total: 2 cur: 1 index: 4 array: [ 1, 2, 3, 1, 1 ]
total 3

此外,reduce()对于数组去重、求最大值、最小值以及数组中元素为引用值的处理更方便。

数组去重:(也可以用Set()去重)
let numbers = [1, 2, 3, 1, 1, 2];
let newArr = [];
numbers.reduce(function(map, cur) {
    console.log(map);
    if (!map.has(cur)) {
        newArr.push(cur);
        map.set(cur, 1)
    }
    return map;
}, new Map())
console.log('newArr', newArr);

Map(0) {}
Map(1) { 1 => 1 }
Map(2) { 1 => 1, 2 => 1 }
Map(3) { 1 => 1, 2 => 1, 3 => 1 }
Map(3) { 1 => 1, 2 => 1, 3 => 1 }
Map(3) { 1 => 1, 2 => 1, 3 => 1 }
newArr [ 1, 2, 3 ]

数组中元素为引用值的处理:
let cart = [
    { name: 'iphone', price: 12000 },
    { name: 'imac', price: 25000 },
    { name: 'ipad', price: 3500 }
]

function getNameByPrice(goods, price) {
    return goods.reduce((arr, cur) => {
        if (cur.price > price) arr.push(cur);
        return arr;
    }, [])
}
console.table(getNameByPrice(cart, 10000))

┌─────────┬──────────┬───────┐
│ (index) │   name   │ price │
├─────────┼──────────┼───────┤
│    0'iphone'12000 │
│    1'imac'25000 │
└─────────┴──────────┴───────┘

reduceRight()方法与reduce()类似,只是方向相反。

let arr = [1, 2, 3, 4, 5]
let sum = arr.reduceRight(function(sum, cur, index, array) {
    console.log('sum:', sum, 'cur:', cur, 'index:', index, 'array:', array);
    return cur + sum;
})
console.log('sum', sum);

sum: 5  cur: 4 index: 3 array: [ 1, 2, 3, 4, 5 ]
sum: 9  cur: 3 index: 2 array: [ 1, 2, 3, 4, 5 ]
sum: 12 cur: 2 index: 1 array: [ 1, 2, 3, 4, 5 ]
sum: 14 cur: 1 index: 0 array: [ 1, 2, 3, 4, 5 ]
sum 15