10 ES6标准入门(Iterator)

Iterator(遍历器)的概念

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

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

遍历器对象本质上,就是一个指针对象,每次调用指针对象的next方法,依次返回数据结构的每个成员

下面是一个模拟next方法返回值的例子

function makeIterator(arr) {
  let index = 0;
  return {
    next: function() { // 闭包
      return {
        value: arr[index++], done: index === arr.length
      }
    }
  }
}
let array = [5, 3, 1];
let result = makeIterator(array);

默认Iterator接口

一种数据结构只要部署了Iterator接口,我们就称这种数据结构是“可遍历的”(iterable)。

ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性([Symbol.iterator]

const obj = {
  [Symbol.iterator] : function () {
    return {
      next: function () {
        return {
          value: 1,
          done: true
        };
      }
    };
  }
};

上面代码中,对象obj是可遍历的(iterable),因为具有Symbol.iterator属性。执行这个属性,会返回一个遍历器对象。该对象的根本特征就是具有next方法。每次调用next方法,都会返回一个代表当前成员的信息对象,具有valuedone两个属性。

ES6的有些数据结构原生具备Iterator接口(比如数组),即不用任何处理,就可以被for...of循环遍历。原因在于,这些数据结构原生部署了Symbol.iterator属性,另外一些数据结构没有(比如对象)。凡是部署了Symbol.iterator属性的数据结构,就称为部署了遍历器接口。调用这个接口,就会返回一个遍历器对象。

原生具备Iterator接口的数据结构如下。
- Array
- Map
- Set
- String
- TypedArray
- 函数的arguments对象
- NodeList对象

对于类似数组的对象(存在数值键名和length属性),部署 Iterator 接口,有一个简便方法,就是Symbol.iterator方法直接引用数组的 Iterator 接口。

let iterable = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3,
  [Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable) {
  console.log(item); // 'a', 'b', 'c'
}

调用 Iterator 接口的场合

有一些场合会默认调用 Iterator 接口(即Symbol.iterator方法),除了下文会介绍的for…of循环,还有几个别的场合。

  • 解构赋值
  • 扩展运算符
  • yield*

for...of循环

for...of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、Generator对象,以及字符串。

for...of循环内部调用的是数据结构的Symbol.iterator方法。

JavaScript原有的for...in循环,只能获得对象的键名,不能直接获取键值。for...of循环,允许遍历获得键值。

for...of循环调用遍历器接口,数组的遍历器接口只返回具有数字索引的属性。这一点跟for...in循环也不一样。

let arr = [3, 5, 7];
arr.foo = 'hello';

for (let i in arr) {
  console.log(i); // "0", "1", "2", "foo"
}

for (let i of arr) {
  console.log(i); //  "3", "5", "7"
}

在对Set和Map结构进行遍历时要注意两点:
1. 遍历的顺序是按照各个成员被添加进数据结构的顺序
2. Set结构遍历时,返回的是一个值,而Map结构遍历时,返回的是一个数组,该数组的两个成员分别为当前Map成员的键名和键值。

对象因为没有部署Iterator接口,所以不能使用for...of循环

与其他遍历语法的比较

最原始的写法就是for循环

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

forEach使用更加简便,但是无法使用breakreturn中途跳出循环

myArray.forEach(function (value) {
  console.log(value);
});

for...in可以遍历数组的键名,主要是为遍历对象而设计的,不适用于遍历数组。

for (var index in myArray) {
  console.log(myArray[index]);
}

for...of循环相比上面几种做法,有一些显著的优点。
- 有着同for...in一样的简洁语法,但是不像for...in那样存在遍历顺序不确定、遍历原型链的属性等缺点
- 不同于forEach方法,它可以与breakcontinuereturn配合使用。
- 提供了遍历所有数据结构的统一操作接口。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值