迭代器.001

前言

数据遍历是我们日常开发中经常用到的逻辑,除了最常见的 for、while、forEach 外,迭代器也提供了数据遍历的接口,了解迭代器有助于我们更好地进行数据处理。

Iterator

Iterator 是 ES6 引入的一种新的遍历机制,迭代器有两个核心概念:

  • 迭代器是一个统一的接口,它的作用是使各种数据结构可被便捷的访问,它是通过一个键为Symbol.iterator 的方法来实现。
  • 迭代器是用于遍历数据结构元素的指针(如数据库中的游标)。

迭代过程

迭代的过程如下:

  • 通过 Symbol.iterator 创建一个迭代器,指向当前数据结构的起始位置
  • 随后通过 next 方法进行向下迭代指向下一个位置, next 方法会返回当前位置的对象,对象包含了 value 和 done 两个属性, value 是当前属性的值, done 用于判断是否遍历结束
  • 当 done 为 true 时则遍历结束

下面通过一个简单的例子进行说明:

  1. const items = ["zero", "one", "two"];
  2. const it = items[Symbol.iterator]();
  3. it.next();
  4. >{value: "zero", done: false}
  5. it.next();
  6. >{value: "one", done: false}
  7. it.next();
  8. >{value: "two", done: false}
  9. it.next();
  10. >{value: undefined, done: true}

上面的例子,首先创建一个数组,然后通过 Symbol.iterator 方法创建一个迭代器,之后不断的调用 next 方法对数组内部项进行访问,当属性 done 为 true 时访问结束。

迭代器是协议(使用它们的规则)的一部分,用于迭代。该协议的一个关键特性就是它是顺序的:迭代器一次返回一个值。这意味着如果可迭代数据结构是非线性的(例如树),迭代将会使其线性化。

可迭代的数据结构

以下是可迭代的值:

  • Array
  • String
  • Map
  • Set
  • Dom元素(正在进行中)

我们将使用 for…of 循环(参见下文的 for…of 循环)对数据结构进行迭代。

Array

数组 ( Array ) 和类型数组 ( TypedArray ) 他们是可迭代的。

  1. for (let item of ["zero", "one", "two"]) {
  2. console.log(item);
  3. }
  4. // output:
  5. // zero
  6. // one
  7. // two

String

字符串是可迭代的,单他们遍历的是 Unicode 码,每个码可能包含一个到两个的 Javascript 字符。

  1. for (const c of 'z\uD83D\uDC0A') {
  2. console.log(c);
  3. }
  4. // output:
  5. // z
  6. // \uD83D\uDC0A

Map

Map 主要是迭代它们的 entries ,每个 entry 都会被编码为 [key, value] 的项, entries 是以确定的形势进行迭代,其顺序是与添加的顺序相同。

  1. const map = new Map();
  2. map.set(0, "zero");
  3. map.set(1, "one");
  4. for (let item of map) {
  5. console.log(item);
  6. }
  7. // output:
  8. // [0, "zero"]
  9. // [1, "one"]

注意: WeakMaps 不可迭代

Set

Set 是对其元素进行迭代,迭代的顺序与其添加的顺序相同

  1. const set = new Set();
  2. set.add("zero");
  3. set.add("one");
  4. for (let item of set) {
  5. console.log(item);
  6. }
  7. // output:
  8. // zero
  9. // one

注意: WeakSets 不可迭代

arguments

arguments 目前在 ES6 中使用越来越少,但也是可遍历的

  1. function args() {
  2. for (let item of arguments) {
  3. console.log(item);
  4. }
  5. } args("zero", "one");
  6. // output:
  7. // zero
  8. // one

普通对象不可迭代

普通对象是由 object 创建的,不可迭代:

  1. // TypeError
  2. for (let item of {}) {
  3. console.log(item);
  4. }

for…of循环

for…of 是 ES6 新引入的循环,用于替代 for..in 和 forEach() ,并且支持新的迭代协议。它可用于迭代常规的数据类型,如 ArrayStringMapSet 等等。

迭代常规数据类型

Array

  1. const nums = ["zero", "one", "two"];
  2. for (let num of nums) {
  3. console.log(num);
  4. }
  5. // TypedArray
  6. const typedArray1 = new Int8Array(6);
  7. typedArray1[0] = 10;
  8. typedArray1[1] = 11;
  9. for (let item of typedArray1) {
  10. console.log(item);
  11. }

String

  1. const str = "zero";
  2. for (let item of str) {
  3. console.log(item);
  4. }

Map

  1. let myMap = new Map();
  2. myMap.set(0, "zero");
  3. myMap.set(1, "one");
  4. myMap.set(2, "two");
  5. // 遍历 key 和 value
  6. for (let [key, value] of myMap) {
  7. console.log(key + " = " + value);
  8. }
  9. for (let [key, value] of myMap.entries()) {
  10. console.log(key + " = " + value);
  11. }
  12. // 只遍历 key
  13. for (let key of myMap.keys()) {
  14. console.log(key);
  15. }
  16. // 只遍历 value
  17. for (let value of myMap.values()) {
  18. console.log(value);
  19. }

Set

  1. let mySet = new Set();
  2. mySet.add("zero");
  3. mySet.add("one");
  4. mySet.add("two");
  5. // 遍历整个 set
  6. for (let item of mySet) {
  7. console.log(item);
  8. }
  9. // 只遍历 key 值
  10. for (let key of mySet.keys()) {
  11. console.log(key);
  12. }
  13. // 只遍历 value
  14. for (let value of mySet.values()) {
  15. console.log(value);
  16. }
  17. // 遍历 key 和 value ,两者会相等
  18. for (let [key, value] of mySet.entries()) {
  19. console.log(key + " = " + value);
  20. }

可迭代的数据结构

of 操作数必须是可迭代,这意味着如果是普通对象则无法进行迭代。如果数据结构类似于数组的形式,则可以借助 Array.from() 方法进行转换迭代。

  1. const arrayLink = {
  2. length: 2,
  3. 0: "zero",
  4. 1: "one"
  5. }
  6. // 报 TypeError 异常
  7. for (let item of arrayLink) {
  8. console.log(item);
  9. }
  10. // 正常运行
  11. for (let item of Array.from(arrayLink)) {
  12. console.log(item);
  13. }
  14. // output:
  15. // zero
  16. // one

let 、const 和 var 用于 for..of

如果使用 let 和 const ,每次迭代将会创建一个新的存储空间,这可以保证作用域在迭代的内部。

  1. const nums = ["zero", "one", "two"];
  2. for (const num of nums) {
  3. console.log(num);
  4. }
  5. // 报 ReferenceError
  6. console.log(num);

从上面的例子我们看到,最后一句会报异常,原因 num 的作用域只在循环体内部,外部无效。使用 var 则不会出现上述情况,因为 var 会作用于全局,迭代将不会每次都创建一个新的存储空间。

  1. const nums = ["zero", "one", "two"];
  2. forv (var num of nums) {
  3. console.log(num);
  4. }
  5. console.log(num);
  6. // output: two

总结

~

~ 本文完,感谢阅读!

~

学习有趣的知识,结识有趣的朋友,塑造有趣的灵魂!

大家好,我是〖编程三昧〗的作者 隐逸王,我的公众号是『编程三昧』,欢迎关注,希望大家多多指教!

更多相关文章

  1. 前端之路,论算法的重要性!不要与高薪大厂,职级晋升,失之交臂
  2. JS获取表单元素、dom树遍历增删改、操作元素内容、自定义属性、
  3. 多维数组遍历,购物车总金额实例
  4. php中遍历数组和购物车结算应用
  5. php变量的8种类型. 遍历php多维数组(foreach与for) 一个函数完成购
  6. Java数据结构之平衡二叉树的原理与实现
  7. Java数据结构之平衡二叉树的原理与实现
  8. php变量的8种类型 遍历php多维数组(foreach与for) 一个函数完成购
  9. 遍历Android(安卓)SD卡

随机推荐

  1. 如何使用asp.net实现文件和文件夹的复制
  2. 详解ASP.NET中连接数据库配置方法
  3. asp.net利用ashx实现验证码功能详解
  4. 在ASP.NET中实现DES加密与解密MD5加密功
  5. 在Asp.net的MVC中利用swupload实现多图片
  6. 支付宝的支付接口在.net中的使用
  7. C#中关于AutoMapper应用的实例
  8. 使用Asp.net实现信息管理系统的数据统计
  9. .net MVC中forms验证的使用实例详解
  10. 比较.NET中接口与类