ES6 迭代器和 for.of循环(详细教程)
这篇文章主要介绍了ES6 迭代器(Iterator)和 for.of循环使用方法学习总结,现在分享给大家,也给大家做个参考。
一、什么是迭代器?
生成器概念在Java,Python等语言中都是具备的,ES6也添加到了JavaScript中。Iterator可以使我们不需要初始化集合,以及索引的变量,而是使用迭代器对象的 next 方法,返回集合的下一项的值,偏向程序化。
迭代器是带有特殊接口的对象。含有一个next()方法,调用返回一个包含两个属性的对象,分别是value和done,value表示当前位置的值,done表示是否迭代完,当为true的时候,调用next就无效了。
ES5中遍历集合通常都是 for循环,数组还有 forEach 方法,对象就是 for-in,ES6 中又添加了 Map 和 Set,而迭代器可以统一处理所有集合数据的方法。迭代器是一个接口,只要你这个数据结构暴露了一个iterator的接口,那就可以完成迭代。ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费。
二、如何使用迭代器?
1、默认 Iterator 接口
数据结构只要部署了 Iterator 接口,我们就成这种数据结构为“可遍历”(Iterable)。ES6 规定,默认的 Iterator 接口部署在数据结构的 Symbol.iterator 属性,或者说,一个数据结构只要具有 Symbol.iterator 数据,就可以认为是“可遍历的”(iterable)。
可以供 for...of 消费的原生数据结构
Array
Map
Set
String
TypedArray(一种通用的固定长度缓冲区类型,允许读取缓冲区中的二进制数据)
函数中的 arguments 对象
NodeList 对象
可以看上面的原生数据结构中并没有对象(Object),为什么呢?
那是因为对象属性的遍历先后顺序是不确定的,需要开发者手动指定。本质上,遍历器是一种线性处理,对于任何非线性的数据结构,部署遍历器接口就等于部署一种线性变换。
做如下处理,可以使对象供 for...of 消费:
// code1 function Obj(value) { this.value = value; this.next = null; } Obj.prototype[Symbol.iterator] = function() { var iterator = { next: next }; var current = this; function next() { if (current) { var value = current.value; current = current.next; return { done: false, value: value }; } else { return { done: true }; } } return iterator; } var one = new Obj(1); var two = new Obj(2); var three = new Obj(3); one.next = two; two.next = three; for (var i of one) { console.log(i); } // 1 // 2 // 3
2、调用 Iterator 接口的场合
(1) 解构赋值
// code2 let set = new Set().add('a').add('b').add('c'); let [x,y] = set; // x='a'; y='b' let [first, ...rest] = set; // first='a'; rest=['b','c'];
(2) 扩展运算符
// code3 // 例一 var str = 'hello'; [...str] // ['h','e','l','l','o'] // 例二 let arr = ['b', 'c']; ['a', ...arr, 'd'] // ['a', 'b', 'c', 'd']
(3)Generator 函数中的 yield* 表达式(下一章介绍)
// code4 let generator = function* () { yield 1; yield* [2,3,4]; yield 5; }; var iterator = generator(); iterator.next() // { value: 1, done: false } iterator.next() // { value: 2, done: false } iterator.next() // { value: 3, done: false } iterator.next() // { value: 4, done: false } iterator.next() // { value: 5, done: false } iterator.next() // { value: undefined, done: true }
(4)其它场合
for..of
Array.from
Map()、Set()、WeakMap()、WeakSet()
Promise.all()
Promise.race()
3、for...of 循环的优势
先看看,数组 forEach 方法的缺点:
// code5 myArray.forEach(function (value) { console.log(value); });
这个写法的问题在于,无法中途跳出 forEach 循环,break 命令或 return 命令都不能生效。
再看看,对象 for...in 的循环的缺点:
for (var index in myArray) { console.log(myArray[index]); };
数组的键名是数字,但是 for...in 循环是以字符串作为键名,“0”、“1”、“2”等。
for...in 循环不仅可以遍历数字键名,还会遍历手动添加的期推荐,甚至包括原型链上的键。
某些情况下,for...in 循环会议任意顺序遍历键名
for...in 遍历主要是为遍历对象而设计的,不适用于遍历数组
那么,for...of 有哪些显著的优点呢?
有着同 for...in 一样的简洁语法,但是没有 for...in 那些缺点
不同于 forEach 方法,它可以与 break、continue 和 return 配合使用
提供了遍历所有数据结构的统一操作接口
for (var n of fibonacci) { if (n > 1000) { break; console.log(n); } }
4、各数据类型如何使用 for...of 循环?
(1)数组
for...of 循环允许遍历数组获得键值
var arr = ['a', 'b', 'c', 'd']; for (let a in arr) { console.log(a); // 0 1 2 3 } for (let a of arr) { console.log(a); // a b c d }
for...of 循环调用遍历器接口,数组的遍历器接口只返回具有数字索引的值
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" }
(2)Map 和 Set 结构
var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]); for (var e of engines) { console.log(e); } // Gecko // Trident // Webkit var es6 = new Map(); es6.set("edition", 6); es6.set("committee", "TC39"); es6.set("standard", "ECMA-262"); for (var [name, value] of es6) { console.log(name + ": " + value); } // edition: 6 // committee: TC39 // standard: ECMA-262
由上述的代码可以看出,for...of 循环遍历Map 和 Set 结构时,遍历的顺序是按照各个成员被添加进数据结构的顺序,Set 结构遍历时返回的是一个值,而 Map 结构遍历时返回的是一个数组,该数组的两个成员分别为当前 Map 成员的键名和键值。
(3)类数组对象
字符串
// 普通的字符串遍历 let str = "yuan"; for (let s of str) { console.log(s); // y u a n } // 遍历含有 32位 utf-16字符的字符串 for (let x of 'a\uD83D\uDC0A') { console.log(x); } // 'a' // '\uD83D\uDC0A'
DOM NodeList 对象
let paras = document.querySelectorAll("p"); for (let p of paras) { p.classList.add("test"); }
arguments 对象
function printArgs() { for (let x of arguments) { console.log(x); } } printArgs("a", "n"); // "a" // "n"
没有 Iterator 接口类数组对象的遍历处理
借用 Array.from 方法处理
let arrayLike = { length: 2, 0 : 'a', 1 : 'b' }; // 报错 for (let x of arrayLike) { console.log(x); } // 正确 for (let x of Array.from(arrayLike)) { console.log(x); }
(4)对象
对于普通对象,不能直接使用 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
三、迭代器应用实例
1、斐波那契数列
下面我们就使用迭代器来自定义自己的一个斐波那契数列组,我们直到斐波那契数列有两个运行前提,第一个前提是初始化的前两个数字为0,1,第二个前提是将来的每一个值都是前两个值的和。这样我们的目标就是每次都迭代输出一个新的值。
var it = { [Symbol.iterator]() { return this }, n1: 0, n2: 1, next() { let temp1 = this.n1, temp2 = this.n2; [this.n1, this.n2] = [temp2, temp1 + temp2] return { value: temp1, done: false } } } for (var i = 0; i < 20; i++) { console.log(it.next()) } // "value": 0, "done": false } { "value": 1, "done": false } { "value": 1, "done": false } { "value": 2, "done": false } { "value": 3, "done": false } { "value": 5, "done": false }... { "value": 2584, "done": false } { "value": 4181, "done": false }
2、任务队列迭代器
我们可以定义一个任务队列,该队列初始化时为空,我们将待处理的任务传递后,传入数据进行处理。这样第一次传递的数据只会被任务1处理,第二次传递的只会被任务2处理… 代码如下:
var Task = { actions: [], [Symbol.iterator]() { var steps = this.actions.slice(); return { [Symbol.iterator]() { return this; }, next(...args) { if (steps.length > 0) { let res = steps.shift()(...args); return { value: res, done: false } } else { return { done: true } } } } } } Task.actions.push(function task1(...args) { console.log("任务一:相乘") return args.reduce(function(x, y) { return x * y }) }, function task2(...args) { console.log("任务二:相加") return args.reduce(function(x, y) { return x + y }) * 2 }, function task3(...args) { console.log("任务三:相减") return args.reduce(function(x, y) { return x - y }) }); var it = Task[Symbol.iterator](); console.log(it.next(10, 100, 2)); console.log(it.next(20, 50, 100)) console.log(it.next(10, 2, 1)) // 任务一:相乘 { "value": 2000, "done": false }任务二:相加 { "value": 340, "done": false }任务三:相减 { "value": 7, "done": false }
3、延迟执行
假设我们有一个数据表,我们想按大小顺序依次的获取数据,但是我们又不想提前给他排序,有可能我们根本就不去使用它,所以我们可以在第一次使用的时候再排序,做到延迟执行代码:
var table = { "d": 1, "b": 4, "c": 12, "a": 12 } table[Symbol.iterator] = function() { var _this = this; var keys = null; var index = 0; return { next: function() { if (keys === null) { keys = Object.keys(_this).sort(); } return { value: keys[index], done: index++>keys.length }; } } } for (var a of table) { console.log(a) } // a b c d
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
以上是ES6 迭代器和 for.of循环(详细教程)的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

C#中如何使用迭代器和递归算法处理数据,需要具体代码示例在C#中,迭代器和递归算法是两种常用的数据处理方法。迭代器可以帮助我们遍历集合中的元素,而递归算法则能够有效地处理复杂的问题。本文将详细介绍如何使用迭代器和递归算法来处理数据,并提供具体的代码示例。使用迭代器处理数据在C#中,我们可以使用迭代器来遍历集合中的元素,而无需事先知道集合的大小。通过迭代器,我

async是es7的。async和await是ES7中新增内容,是对于异步操作的解决方案;async/await可以说是co模块和生成器函数的语法糖,用更加清晰的语义解决js异步代码。async顾名思义是“异步”的意思,async用于声明一个函数是异步的;async和await有一个严格规定,两者都离不开对方,且await只能写在async函数中。

为了浏览器兼容。ES6作为JS的新规范,加入了很多新的语法和API,但现代浏览器对ES6新特性支持度不高,所以需将ES6代码转为ES5代码。在微信web开发者工具中,会默认使用babel将开发者ES6语法代码转换为三端都能很好支持的ES5的代码,帮助开发者解决环境不同所带来的开发问题;只需要在项目中配置勾选好“ES6转ES5”选项即可。

在es6中,暂时性死区是一个语法错误,是指let和const命令使区块形成封闭的作用域。在代码块内,使用let/const命令声明变量之前,该变量都是不可用的,在变量声明之前属于该变量的“死区”;这在语法上,称为“暂时性死区”。ES6规定暂时性死区和let、const语句不出现变量提升,主要是为了减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的行为。

Golang是一个快速、高效的静态编译型语言,其简洁的语法和强大的性能让它在软件开发领域备受青睐。在Golang中,迭代器(Iterator)是一种常用的设计模式,用于遍历集合中的元素而无需暴露集合的内部结构。本文将详细介绍如何在Golang中实现和使用迭代器,通过具体的代码示例帮助读者更好地理解。1.迭代器的定义在Golang中,迭代器通常由一个接口和实

PHP程序中的迭代器最佳实践迭代器在PHP编程中是一种非常常用的设计模式。通过实现迭代器接口,我们可以遍历一个集合对象中的元素,而且还可以轻松的实现自己的迭代器对象。在PHP中,迭代器模式可以帮助我们更有效地操作数组、列表等集合对象。在本文中,我们将介绍PHP程序中迭代器的最佳实践,希望能帮助同样在迭代器应用方面工作的PHP开发人员。一、使用标准迭代器接口P

ES6 import会产生变量提升的现象。变量提升是将变量声明提升到它所在作用域的最开始的部分。js要经历编译跟执行阶段,在编译阶段的时候,会搜集所有的变量声明并且提前声明变量,而其他的语句都不会改变他们的顺序,因此,在编译阶段的时候,第一步就已经执行了,而第二部则是在执行阶段执行到该语句的时候才执行。
