es6学习笔记--Interator和Generator(以及for-of的用法)
Interator(遍历器)
在 JavaScript 中 迭代器是一个对象,它提供了一个next() 方法,(除了next()方法还有return和throw方法),用来返回序列中的下一项。这个方法返回包含两个属性:done和 value。done属性是个布尔值,代表遍历是否结束,即是否还有必要再一次调用next方法。value属性代表当前成员的值。
迭代器对象一旦被创建,就可以反复调用next()。
function makeIterator(array){
var nextIndex = 0;
return {
next: function(){
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{done: true};
}
};
}
let a = makeIterator(['apple','pear','orange'])
console.log(a.next()) // {value: "apple", done: false}
console.log(a.next()) // {value: "pear", done: false}
console.log(a.next()) // {value: "orange", done: false}
console.log(a.next()) // {done: true}
ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性, Symbol.iterator属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。
学习一下新型的for-of循环。可在具有Iterator 接口的元素进行遍历。
let arr = [1,2,3];
for(let v of arr){
v +=1;
console.log(v)
} // 2 3 4
[1,2,3,4,5].forEach((i,v) => {
console.log(v)
if(i > 3){
break;
}
}) // Uncaught SyntaxError: Illegal break statement
for(let v in ['a','b','c']){
console.log(v)
} // 0 1 2
let arr = [1,2,3,4];
for(let v of arr){
console.log(v)
} // 1 2 3 4
let a = ['a','b','c','d']
for(let v of a){
console.log(v)
} // a b c d
for(let v of [1,2,3,4,5]){
console.log(v)
if(v > 3){
break
}
} // 1 2 3 4 5
3 可以遍历其他的所有集合(Nodelist,Set,Map),还有生成器
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div> let doms = document.querySelectorAll('div')
for(let v of doms){
console.log(v.innerHTML)
} // 1 2 3 4
let set = new Set([1,2,3,4,5])
for(let v of set){
console.log(v)
} // 1 2 3 4 5
let map = new Map().set('a',1).set('b',2)
for(let v of map){
console.log(v)
}
// ["a", 1]
// ["b", 2]
let obj = {name:'peter',age:25}
for(let v of obj){
console.log(v)
} // Uncaught TypeError: obj is not iterable
let obj = {name:'peter',age:25}
for(let v of Object.keys(obj)){
console.log(v)
} // name age
4 另外,for-of可以适用于字符串
let str = 'hello';
for(let v of str) {
console.log(v)
} // h e l l o
Interator不是很难懂,只要明白了哪些是数据集合,就说明具有Interator接口,自然就可以当作遍历器,从而使用for-of循环和使用next方法获取想要的数据。
Generator(生成器)
通过对Interator的理解,生成器也是具有Interator接口的对象,它本身带有遍历特性,返回一个遍历器对象。
既然生成器是遍历器,那么可以使用遍历器的方法(本身函数不会实行,必须通过next()方法才能调用或者使用for-of返回)
function *fn(){
yield 'peter';
yield 1;
yield {name:'peter'};
yield [1,2,3,4];
yield function *foo(){
yield 123;
}
}
let a = fn()
console.log(a.next())
console.log(a.next())
console.log(a.next())
console.log(a.next())
console.log(a.next())
console.log(a.next())
{value: "peter", done: false}
{value: 1, done: false}
{value: {…}, done: false}
{value: Array(4), done: false}
{value: ƒ, done: false}
{value: undefined, done: true}
学习一下yield:
function *fn(){
yield 'a';
let b = yield 'b' + 'c';
yield 'd'
}
let foo = fn()
for(let v of foo){
console.log(v)
} // a bc d
function *fn(){
yield '1'
console.log('start')
yield '2'
}
let a = fn()
console.log(a.next())
{value: "1", done: false}
function fn(){
yield 'a'
}
fn() // Uncaught SyntaxError: Unexpected string
function *fn(){
yield '1';
yield '2';
return '3';
yield '4'
}
let a = fn()
console.log(a.next()); // {value: "1", done: false}
console.log(a.next()); // {value: "2", done: false}
console.log(a.next()); // {value: "3", done: true}
console.log(a.next()); // {value: undefined, done: true}
console.log(a.next()); // {value: undefined, done: true}
function *foo(){
yield 'f'
}
function *fn(){
yield 'a';
yield foo()
yield 'b'
}
for( let v of fn()){
console.log(v)
} // a foo {<suspended>} b
function *foo(){
yield 1;
yield 2
}
function *fn(){
yield 'a';
yield *foo()
yield 'b'
}
for( let v of fn()){
console.log(v) // a 1 2 b
}
上面已经说到生成器也是具有Interator接口的对象,不可置否的,生成器本身带有Symbol.iterator,可以说生成器是遍历器的一种,所以可遍历,可以使用for-of来循环数据。
for...of循环可以自动遍历 Generator 函数时生成的Iterator对象,且此时不再需要调用next方法。
function *fn(){
yield 'a';
yield 'b';
yield 'c';
yield 'd';
return 'end'
}
let a = fn()
for(let v of a){
console.log(v) // a b c d
}
function *fn(){
yield 'a';
yield 'b';
yield 'c';
yield 'd';
return 'end'
}
let a = fn()
console.log(a.next()); // {value: "a", done: false}
console.log(a.next()); // {value: "b", done: false}
console.log(a.next()); // {value: "c", done: false}
console.log(a.next()); // {value: "d", done: false}
console.log(a.next()); // {value: "end", done: true}
console.log(a.next()); // {value: undefined, done: true}
function *fn(){
yield 'a';
yield 'b';
yield 'c';
yield 'd';
return 'end'
}
let a = fn()
console.log([...a]) // ["a", "b", "c", "d"]
概要总结;只要具有Symbol.iterator属性的,就可以遍历yield表达式
function* f() {
yield 2;
yield 3;
}
new f() // TypeError: F is not a constructor
Generator 函数的方法:
next() 返回 Generator 函数对象中yield后面的表达式,上面已经用到了next方法。yield表达式本身没有返回值,总是返回undefined
function *fn(x){
let a = yield x;
let b = yield 2 + a;
}
let a = fn(2);
console.log(a.next(5)); // {value: 2, done: false}
console.log(a.next(10)); // {value: 12, done: false}
console.log(a.next(20)); // {value: undefined, done: true}
function *fn(x){
let a = yield x;
let b = yield 2 + a;
}
let a = fn(2);
console.log(a.next()); // {value: 2, done: false}
console.log(a.next()); // {value: NaN, done: false}
console.log(a.next()); // {value: undefined, done: true}
throw() 在函数体外抛出错误,然后在 Generator 函数体内捕获。
let a = function* () {
try {
yield ;
} catch ( e ){
console.log(e);
}
};
var i = a();
console.log(i.throw()) // Uncaught undefined
let g = function* () {
try {
yield 1;
} catch (e) {
console.log(e);
}
yield 'a';
yield 'b'
};
let i = g();
console.log(i.next()) //
i.throw(new Error('出错了!')); // Error: 出错了!(…) 附带执行了一次yield ‘a’
console.log(i.next()) // b
throw()方法的作用就是捕获异常,并且继续执行下去,不因为异常而中断。throw方法被捕获以后,会附带执行下一条yield表达式。也就是说,会附带执行一次next方法。
throw()的意义:大大方便了对错误的处理。多个yield表达式,可以只用一个try...catch代码块来捕获错误。如果使用回调函数的写法,想要捕获多个错误,就不得不为每个函数内部写一个错误处理语句,现在只在 Generator 函数内部写一次catch语句就可以了。
return() 返回给定的值,并且终结遍历 Generator 函数。
function *fn(){
yield 1;
yield 2;
return 3;
}
let a = fn();
console.log(a.next()) // {value: 1, done: false}
console.log(a.return()); // {value: undefined, done: true}
console.log(a.next()) // {value: undefined, done: true}
function *fn(){
yield 1;
yield 2;
return 3;
}
let a = fn();
console.log(a.next()) // {value: 1, done: false}
console.log(a.return(100)); // {value: 100, done: true}
console.log(a.next()) // {value: undefined, done: true}
return()的意义:通常在生成器异步操作时需要在某个时段跳出来。
Generator生成器是异步编程提供了方便。
对于Interator和Generator,在平时使用时很少用到,只有那个for-of可以替代for循环使用,主要用于异步编程async当中。学习这个感觉没学全,过后我会再仔细学一遍。知识点我放到github里了,有需要可以去下载一起学习。
还是那句话。有什么问题或错误请私信或者下方评论,一起讨论进步。
参考资料:
阮一峰es6入门 http://es6.ruanyifeng.com/
es6学习笔记--Interator和Generator(以及for-of的用法)的更多相关文章
- es6学习笔记-class之一概念
前段时间复习了面向对象这一部分,其中提到在es6之前,Javasript是没有类的概念的,只从es6之后出现了类的概念和继承.于是乎,花时间学习一下class. 简介 JavaScript 语言中,生 ...
- ES6学习笔记<三> 生成器函数与yield
为什么要把这个内容拿出来单独做一篇学习笔记? 生成器函数比较重要,相对不是很容易理解,单独做一篇笔记详细聊一聊生成器函数. 标题为什么是生成器函数与yield? 生成器函数类似其他服务器端语音中的接口 ...
- ES6学习笔记<五> Module的操作——import、export、as
import export 这两个家伙对应的就是es6自己的 module功能. 我们之前写的Javascript一直都没有模块化的体系,无法将一个庞大的js工程拆分成一个个功能相对独立但相互依赖的小 ...
- ES6学习笔记<四> default、rest、Multi-line Strings
default 参数默认值 在实际开发 有时需要给一些参数默认值. 在ES6之前一般都这么处理参数默认值 function add(val_1,val_2){ val_1 = val_1 || 10; ...
- ES6学习笔记<二>arrow functions 箭头函数、template string、destructuring
接着上一篇的说. arrow functions 箭头函数 => 更便捷的函数声明 document.getElementById("click_1").onclick = ...
- ES6学习笔记<一> let const class extends super
学习参考地址1 学习参考地址2 ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准.因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015:也 ...
- ES6学习笔记之块级作用域
ES6学习笔记:块级作用域 作用域分类 全局作用域 局部作用域 块级作用域 全局作用域示例 var i=2; for (var i = 0; i < 10; i++) { } console.l ...
- ES6学习笔记之变量的解构赋值
变量的解构赋值 ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构. 数组的解构赋值 以前,为变量赋值,只能直接指定值: 1 2 3 var a = 1; var b = 2; ...
- ES6学习笔记(三):教你用js面向对象思维来实现 tab栏增删改查功能
前两篇文章主要介绍了类和对象.类的继承,如果想了解更多理论请查阅<ES6学习笔记(一):轻松搞懂面向对象编程.类和对象>.<ES6学习笔记(二):教你玩转类的继承和类的对象>, ...
随机推荐
- Java过滤XSS脚本, 可通过Appscan扫描
项目中有时会需要把一些报错或者解决方案直接返回给前端, 如果直接返回原字符串, 可能会被恶意传参来实现xss注入. 例如常规业务访问一个页面读取文件&file=sdf.cpt, 如果文件不存在 ...
- 本站已稳定运行了XX天,网页时间显示功能实现方法
这个是我昨晚上添加的效果, 分为三个部分: 1.本站已稳定运行了多少天的实现: 直接把下面代码复制到后台你想添加的位置即可. 1 2 3 4 5 6 7 8 9 本站已稳定运行了 <strong ...
- js操作DOM元素
创建 document.createElement() 查找 document.getElementById() 返回对拥有指定 id 的第一个对象的引用. document.getElement ...
- Jenkins 部署 jmeter + Ant
安装Jenkins: 到jenkins官网下载相应的jenkins版本: 双击jenkins.msi启动安装,安装目录选择D:\Progrom Files\Jenkins,然后启动成功. Jenkin ...
- C#将.spl剥离成.emf文件格式
本文转载自 星战紫辉 http://www.cppblog.com/rawdata/archive/2009/02/23/74653.html 但C#代码实现为本人原创.https://github. ...
- docker初次体验-管理MySQL+tomcat镜像
引言 平时经常用linux,我没少吃苦后悔linux没好好研究研究.装一些软件配一些环境时很是害怕,多亏有了docker.docker是一个应用容器引擎,可以管理很多的软件镜像,这些镜像被官方放在了d ...
- Java中常见的URL问题及解决方案
URL无处不在,不过似乎开发人员并没有真正地理解它们,因为在Stack Overflow上经常看到有人在问如何正确的创建一个URL.想知道URL语法是如何工作的,可以看下兄弟连教育总结的这篇文章,非常 ...
- 简单模拟struts2及struts2的处理流程介绍
用了几天模拟struts2,最后结果还是很成功的,也基本没有什么遇上比较难解决的问题,万事开头难,在最开始的时候无从下手,看着下面这张struts2工作流程图配合着网上的博客看了一天终于有了眉目. 看 ...
- [Tarjan 学习笔记](无向图)
今天考试因为不会敲 Dcc 的板子导致没有AK(还不是你太菜了),所以特地写一篇博客记录 Tarjan 的各种算法 无向图的割点与桥 (各种定义跳过) 割边判定法则 无向边 (x,y) 是桥,当且仅当 ...
- 笔记:Struts2 文件上传和下载
为了上传文件必须将表单的method设置为POST,将 enctype 设置为 muiltipart/form-data,只有设置为这种情况下,浏览器才会把用户选择文件的二进制数据发送给服务器. 上传 ...