写在前面
基于 ES6,不会改变自身的遍历方法一共有 12 个。
分别为 forEach、every、some、filter、map、reduce、reduceRight,
以及 ES6 新增的方法 entries、find、findIndex、keys、values。
// forEach方法 不会返回处理之后的数组
// 注意:forEach里的函数参数传入两个参数时,
// 第一个参数是value,不是key
var array = [1, 3, 5];
var sReturn = array.forEach((value, index, array) => {
array[index] = value;
});
console.log(array); // [1, 3, 5]
console.log(sReturn); // undefined,
// 可见返回值为undefined
// every方法
var o = {0:10, 1:8, 2:25, length:3};
var bool = Array.prototype.every.call(o,(value, index, obj) => {
return value >= 8;
},o);
console.log(bool); // true
// some方法
var array = [18, 9, 10, 35, 80];
var isExist = array.some((value, index, array) => {
return value > 20;
});
console.log(isExist); // true
// map 方法
// map 有{}的时候需要有return 没有{}的时候不需要有return
var array = [18, 9, 10, 35, 80];
array.map(item => item + 1);
array.map((item) => { return item + 1})
console.log(array); // [19, 10, 11, 36, 81]
// filter 方法
var array = [18, 9, 10, 35, 80];
var array2 = array.filter((value, index, array) => {
return value > 20;
});
console.log(array2); // [35, 80]
// reduce方法
var array = [1, 2, 3, 4];
var s = array.reduce((previousValue, value, index, array) => {
return previousValue * value;
},1);
console.log(s); // 24
// ES6写法更加简洁
array.reduce((p, v) => p * v); // 24
// reduceRight方法 (和reduce的区别就是从后往前累计)
var array = [1, 2, 3, 4];
array.reduceRight((p, v) => p * v); // 24
// entries方法
var array = ["a", "b", "c"];
var iterator = array.entries();
console.log(iterator.next().value); // [0, "a"]
console.log(iterator.next().value); // [1, "b"]
console.log(iterator.next().value); // [2, "c"]
console.log(iterator.next().value);
// undefined, 迭代器处于数组末尾时,
// 再迭代就会返回undefined
// find & findIndex方法
var array = [1, 3, 5, 7, 8, 9, 10];
function f(value, index, array){
return value%2==0; // 返回偶数
}
function f2(value, index, array){
return value > 20; // 返回大于20的数
}
console.log(array.find(f)); // 8
console.log(array.find(f2)); // undefined
console.log(array.findIndex(f)); // 4
console.log(array.findIndex(f2)); // -1
// keys方法
[...Array(10).keys()];
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[...new Array(10).keys()];
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
// values方法
var array = ["abc", "xyz"];
var iterator = array.values();
console.log(iterator.next().value);//abc
console.log(iterator.next().value);//xyz
其中,要注意有些遍历方法不会返回处理之后的数组 ,比如 forEach;有些方法会返回处理之后的数组, 比如 filter。这个细节你需要牢记!!!! 这样才会在面试过程中正确作答。
reduce 方法也需要重点关注,其参数复杂且多 ,通常一些复杂的逻辑处理,其实使用 reduce 很容易就可以解决 。reduce 到底能解决什么问题呢?先看下 reduce 的两个参数。
首先是 callback(一个在数组的每一项中调用的函数,接受四个参数):
previousValue(上一次调用回调函数时的返回值,或者初始值)
currentValue(当前正在处理的数组元素)
currentIndex(当前正在处理的数组元素下标)
array(调用 reduce() 方法的数组)
然后是 initialValue(可选的初始值,作为第一次调用回调函数时传给 previousValue 的值)。
光靠文字描述其实看着会比较懵,还是通过一个例子来说明 reduce 的功能到底有多么强大。
/* :数组 arr = [1,2,3,4] 求数组的和:*/
// 第一种方法:
var arr = [1,2,3,4];
var sum = 0;
arr.forEach((e) => {sum += e;}); // sum = 10
// 第二种方法
var arr = [1,2,3,4];
var sum = 0;
arr.map((obj) => sum += obj);
// 第三种方法
var arr = [1,2,3,4];
arr.reduce((pre,cur) => {return pre + cur});
从上面代码可以看出,分别用了 forEach 和 map 都能实现数组的求和 ,其中需要另外新定义一个变量 sum,再进行累加求和, 最后再来看 sum 的值,而 reduce 不仅可以少定义一个变量, 而且也会直接返回最后累加的结果,是不是问题就可以轻松解决了?
那么我们结合一个栗子来看看 reduce 怎么用。
var arr = [
{name: 'brick1'},
{name: 'brick2'},
{name: 'brick3'}
]
希望最后返回到 arr 里面每个对象的 name 拼接数据为 'brick1, brick2 & brick3' ,如果用 reduce 如何实现呢?
var arr = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ];
arr.reduce((prev, current, index, array) => {
if (index === 0){
return current.name;
} else if (index === array.length - 1){
return prev + ' & ' + current.name;
} else {
return prev + ', ' + current.name;
}
}, '');
// 返回结果 "one, two & three"
| 数组分类 | 改变自身方法 | 不改变自身方法 | 遍历方法(不改变自身) |
| --- | --- | | --- | --- |
| ES5 | pop、push、reverse、shift、splice、unshift | concat、join、slice、 toString、toLocaleString、indexOf、lastIndexOf | forEach、 every、 some、 filter、 map、 reduce、 reduceRight
| ES6 / 7 / 8 |copyWithin、fill | includes、toSource | entries、find、findIndex、keys、values
所有插入元素的方法,比如 push、unshift 一律返回数组新的长度;
所有删除元素的方法,比如 pop、shift、splice 一律返回删除的元素,或者返回删除的多个元素组成的数组;
部分遍历方法,比如 forEach、every、some、filter、map、find、findIndex, 它们都包含 function(value,index,array){} 和 thisArg 这样两个形参。
再来看看for in for of
for in 的特点
for ... in 循环返回的值都是数据结构的键值名(适合遍历对象)。 遍历对象返回的对象的key值,遍历数组返回的数组的下标(key)。 for ... in 循环不仅可以遍历数字键名,还会遍历原型上的值和手动添加的其他键。 特别情况下, for ... in 循环会以看起来任意的顺序遍历键名。
const obj = {
a: 1,
b: 2,
c: 3
}
for (let i in obj) {
console.log(i)
// a
// b
// c
}
for (let i of obj) {
console.log(i) // for of只能遍历iterable
// Uncaught TypeError: obj is not iterable 报错了
}
const arr = ['a', 'b', 'c']
// for in 循环
for (let i in arr) {
console.log(i)
// 0
// 1
// 2
}
// for of
for (let i of arr) {
console.log(i)
// a
// b
// c
}
for(let [key, value] of map){...}
//注意这里是[key, value]的形式,
// 跟写入的[ [1, 2], [3, 4] ]的形式是相对应的
const arr = ['a', 'b']
// 手动给 arr数组添加一个属性
arr.name = 'qiqingfu'
// for in 循环可以遍历出 name 这个键名
for (let i in arr) {
console.log(i)
// a
// b
// name
}
在elements对象中,会按照顺序存放排序属性,properties属性则指向了properties对象,在properties对象中,会按照创建时的顺序保存了常规属性。
for of 特点
for of 循环用来获取一对键值对中的值,而 for in 获取的是 键名一个数据结构只要部署了 Symbol.iterator 属性, 就被视为具有 iterator接口, 就可以使用 for of循环。 这个对象,没有Symbol.iterator这个属性,所以使用 for of会报 obj is not iterable for of 不同与 forEach, 它可以与 break、continue和return 配合使用,也就是说 for of 循环可以随时退出循环。 提供了遍历所有数据结构的统一接口。
只要有 iterator 接口的数据结构,都可以使用 for of循环。
- 数组 Array
- Map
- Set
- String
- arguments对象
- Nodelist对象, 就是获取的dom列表集合
如果想让对象可以使用 for of循环怎么办?使用 Object.keys() 获取对象的 key值集合后,再使用 for of进行遍历即可
const obj = {
a: 1,
b: 2,
c: 3
}
for (let i of Object.keys(obj)) {
console.log(i)
// a
// b
// c
}
for (let k of Object.values(obj)) {
console.log(k)
// 1
// 2
// 3
}