es6 for循环_摸鱼ES6:迭代器(Iterator) 及 for-of

90678c3c6a30c388acb83bf4a365a441.png

1. for-of 循环

介绍迭代器之前,先来你可以给任意类型的对象添加迭代器方法。一下for-of循环~

对于for循环,我们最开始用的基本上是这样的:

for (var i = 0; index < arr.length; i++) {
  console.log(arr[i]);
}

这已经是好多年前的知识点了,不过现在也一直被使用着,自从ES5发布后,forEach也可以用来进行循环:

arr.forEach(function (item) {
    console.log(item);
});

forEach 的写法看起来很简洁,但是有一点问题,它不可以使用break中断循环或者return跳出循环到外层函数

接下来ES6的 for-of 闪亮登场

for (var item of arr) {
  console.log(item);
}

for-of不能直接的拿到index索引,因为它循环的是数组的键值,如果你想使用它的index索引,可以利用entries()方法返回数组的键名和键值,来遍历它的键值对,注意:第一个参数是index,第二个是item。

for (var [index,item] of arr.entries()) {
  console.log(index,item);
}

2. 迭代器

迭代器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。

Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of使用。

正如其它语言中的 for/foreach 语句一样,for-of循环语句通过方法调用来遍历各种集合。数组、Maps 对象、Sets 对象以及其它在我们讨论的对象有一个共同点,它们都有一个迭代器方法。

你可以给任意类型的对象添加迭代器方法。当你为对象添加 myObject.toString() 方法后,就可以将对象转化为字符串,同样地,当你向任意对象添加 myObject[Symbol.iterator]() 方法,就可以遍历这个对象了。

好的,我知道你在想什么,那个 [Symbol.iterator] 语法看起来很奇怪,这段代码到底做了什么呢?这里通过 Symbol 处理了一下方法的名称。标准委员会可以把这个方法命名为.iterator() 方法,但是如果你的代码中的对象可能也有一些.iterator() 方法,这一定会让你感到非常困惑。于是在 ES6 标准中使用 symbol 来作为方法名,而不是使用字符串,来实现唯一性。

ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性,或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)。Symbol.iterator属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。至于属性名Symbol.iterator,它是一个表达式,返回Symbol对象的iterator属性,这是一个预定义好的、类型为 Symbol 的特殊值。

for-of 循环首先调用集合的 [Symbol.iterator]() 方法,紧接着返回一个新的迭代器对象。迭代器对象可以是任意具有.next() 方法的对象;for-of 循环将重复调用这个方法,每次循环调用一次。举个例子:

var it = makeIterator(['a', 'b']);

it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }

function makeIterator(array) {
  var nextIndex = 0;
  return {
    next: function() {
      return nextIndex < array.length ?
        {value: array[nextIndex++], done: false} :
        {value: undefined, done: true};
    }
  };
}

每一次调用next方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含value和done两个属性的对象。其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。上面代码定义了一个makeIterator函数,它是一个遍历器生成函数,作用就是返回一个遍历器对象。对数组['a', 'b']执行这个函数,就会返回该数组的遍历器对象(即指针对象)it。

指针对象的next方法,用来移动指针。开始时,指针指向数组的开始位置。然后,每次调用next方法,指针就会指向数组的下一个成员。第一次调用,指向a;第二次调用,指向b。

next方法返回一个对象,表示当前数据成员的信息。这个对象具有value和done两个属性,value属性返回当前位置的成员,done属性是一个布尔值,表示遍历是否结束,即是否还有必要再一次调用next方法。

原生具备 Iterator 接口的数据结构如下。

  • Array
  • Map
  • Set
  • String
  • 函数的 arguments 对象
  • NodeList 对象

下面的例子是数组的Symbol.iterator属性。

let arr = ['a', 'b', 'c'];
let iter = arr[Symbol.iterator]();

iter.next() // { value: 'a', done: false }
iter.next() // { value: 'b', done: false }
iter.next() // { value: 'c', done: false }
iter.next() // { value: undefined, done: true }

对于原生部署 Iterator 接口的数据结构,不用自己写遍历器生成函数,for...of循环会自动遍历它们。除此之外,其他数据结构(主要是对象)的 Iterator 接口,都需要自己在Symbol.iterator属性上面部署,这样才会被for...of循环遍历。

对于普通的对象,for...of结构不能直接使用,会报错,必须部署了 Iterator 接口后才能使用。

一种解决方法是,使用Object.keys方法将对象的键名生成一个数组,然后遍历这个数组。

for (var key of Object.keys(someObject)) {
  console.log(key + ': ' + someObject[key]);
}

另一个方法是使用 Generator 函数将对象重新包装一下。

function* entries(obj) {
  for (let key of Object.keys(obj)) {
    yield [key, obj[key]];
  }
}

for (let [key, value] of entries(obj)) {
  console.log(key, ':', value);
}
// a: 1
// b: 2
// c: 3
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值