Iterator
为什么先讲这个Iterator呢?因为for..of循环的本质就是调用Iterator接口。
Iterator的本质
Iterator是一个接口,所谓接口就是数据结构的入口,通过这个接口就可以访问它。它其实就是一个遍历器对象,为不同的数据结构提供了统一的访问方法,任何部署了这一接口的数据结构我们都可以对他进行遍历操作。
Iterator的内部过程
- 创建了一个指针对象指向数据结构的起始位置
- 调用对象的next方法指向第一个成员 每次调用都会有两个返回值,一个是成员值,还有一个是bool值,这个bool值就是判断有没有遍历到最后一个,下一次还要不要调用next方法
- 如此反复,直到遍历到最后一个成员。
存在Iterator接口的数据结构
- 数组
- 类数组对象
- String
- Map/Set
**他们都是自带这个接口的,配置在Symbol.iterator方法里面,这个方法会生成一个遍历器对象。**我举个简单的例子,你可以在数组的原型中找到它,Array.prototype一直往下翻就能找到它。
注意
Object对象是不自带这个接口的,为什么呢?Object遍历的顺序是不确定的。所以它没有自带的iterator接口,不过你可以自己给她绑定。
for...of循环(以及for..in循环)
上文说到,for...of循环的本质就是调用这个Iterator接口,所以但凡有这个接口的数据结构都能使用for...of进行遍历。换言之,没有这个接口的数据结构使用它进行遍历就会报错。没错我说的就是Object对象。
报错:obj并不是可以迭代的。
for..of和for...in的对比
for..of获取的是值,而不是索引。比如for...of遍历数组获取的就是数组的元素,而for,,,in遍历数组获取的是数组的索引(并且不是number类型,而是String类型),**其实for..in本质上是为了遍历对象服务的,并且它遍历获取的是key值。**而for...of主要为数组服务。
for...of和forEach对比
forEach不能中途跳出循环(break)。
注意
在v-for指令中,我亲身实践v-for in/of是没有区别的。
map方法
要点
遍历数组,使数组的每一个元素都执行参数中的回调函数,再把返回值组成一个新的数组。注意他不会改变原数组。
范式
arr.map(function(n,[index,[arr]]){})
,map参数是一个回调函数。
- 回调函数的第一个参数是当前遍历获取的数组某个元素,必选
- 第二个参数是该元素的index值,可选
- 第三个是遍历的数组,可选
回调函数每次执行都会return一个值,等遍历完成后,这些值就组成了一个新的数组。
example
将当前数组的元素放大二倍
let arr = [1,2,3];
arr.map(function(n){return n*2})//arr.map(n=>2*n)得到了一个新数组
filter方法
要点
过滤掉数组的某些元素,把符合条件的元素,保留下来,组成一个新数组。这个方法也不会改变原数组,还有就是这个方法的回调函数的返回值必须是一个bool值,只有bool值为true的时候,才将其保留下来,为false的话就过滤掉。
范式
arr.filter(function(n,[index,[arr]]){})
,filter参数是一个回调函数。
- 回调函数的第一个参数是当前遍历获取的数组某个元素,必选
- 第二个参数是该元素的index值,可选
- 第三个是遍历的数组,可选
example
获取数组中大于20的元素
let arr = [5,58,9,41];
arr.filter(n=>n>20);//符合条件的数组成一个新数组。不会改变原数组
reduce方法
要点
这个方法比较特别。为什么呢?因为这个总是来做一些汇总操作的,要不就是对所有元素求和啦,要不就是对所有元素求积啦等等。
范式
arr.redcuce(function(pre,n,[index,[arr]]){},[initialValue])
reduce有两个参数:第一个参数是回调函数,必选。第二个参数,是初始值,可选。
回调函数有四个参数:
- 第一个参数是上次回调函数的返回值,或者是初始值(第一次的时候),必选
- 第二个参数是这次遍历到的元素,必选
- 第三个参数是元素的索引值,可选
- 第四个参数是遍历的数组,可选
example
求所有元素的平方的和。
let arr = [1,2,3];
arr.reduce(function(pre,n)
{return pre+n*n},0)//14