[前端漫谈_1] 从 for of 聊到 Generator
栏目: JavaScript · 发布时间: 5年前
内容简介:说起首先我们想一个问题,为什么使用在真正揭开谜底之前,站在
聊聊 for of
说起 for of
相信每个写过 JavaScript
的人都用过 for of
,平时我们用它做什么呢?大多数情况应该就是遍历数组了,当然,更多时候,我们也会用 map()
或者 filer()
来遍历一个数组。 但是就像我们标题里面说的,它跟 Generator
能扯上什么关系呢?
首先我们想一个问题,为什么使用 for of
或者 map()
/ filer()
方法就可以遍历一个数组 (或者类数组对象: Strings
, Maps
, Sets
, arguments
) 呢? 为什么不能用他们来遍历一个对象呢?
你能学到什么
for of iterator for of for of Generator
类数组对象的玄机
在真正揭开谜底之前,站在 for of
的角度想一下,现在让你去遍历一个数组,你需要知道什么信息呢?
- 对应下标的值
- 是否遍历结束的标志
带着这样的思考,我们打印一个数组来看看这里面的玄机:
const numbersArray = [1, 2, 3]; console.dir(numbersArray);
数组 (或者类数组对象: Strings
, Maps
, Sets
, arguments
) 的原型中都实现了一个方法 Symbol.iterator
,问题来了,那么这个 Symbol.iterator
又有什么用呢? 拿出来试一下就知道了:
let iterator = numbersArray[Symbol.iterator](); // 我们把这个 Symbol.iterator 打印一下看看里面到底有些什么 console.dir(iterator);
这里有一个 next()
方法对吗?执行这个 next()
方法:
iterator.next(); // 输出 {value: 1, done: false} iterator.next(); // 输出 {value: 2, done: false} iterator.next(); // 输出 {value: 3, done: false} iterator.next(); // 输出 {value: undefined, done: true}
请注意,当下标超出时,value: undefined
我们发现这个 iterator.next()
每次都返回了一个对象。这对象包含两个信息:当前下标的值,以及遍历是否结束的标志。这印证了我们之前思考,有了这两个信息,你作为 for of
函数,也能打印出数组的每一项了不是吗?
新的问题来了, iterator
到底是何方神圣呢?
iterator
(迭代器) & The iterator protocol
(迭代协议)
聊到了 iterator
我们不得不先说一下 The iterator protocol
(迭代协议)
MDN 上是这么说的: The iterator protocol
允许 JavaScript
对象去定义或定制它们的迭代行为 ,所以上面出现的 Symbol.iterator
这个方法,就是数组对于这个协议的实现。那么按照这个协议,数组是怎么实现了一个 iterator
呢?
这一大段看起来比较费劲,简单来说就像我们上一章节所印证的,它实现的方式是定义了一个 next()
方法,而这个 next()
方法每次被执行都会返回一个对象: {value:xxx/undefined , done: true/false }
其中 value
代表的是当前遍历到的值, done
代表是否遍历结束。
本小节回答了我们之前的提问: 为什么不能用 for of
来遍历一个对象呢? 原因很简单: JavaScript
的对象中没有实现一个这样的 iterator
。你可以打印一个对象来看看结果如何:
console.dir({ a: 1, b: 2 });
okay, 到这里如果就结束的话,那我们了解得还不够深入,于是再问一个问题:
Why is there no built-in object iteration ? (为什么在 object
中没有内置迭代器呢? )
为什么在 object
中没有内置迭代器呢?
对啊,为什么呢? 我们在各样的场景中也需要来遍历一个对象啊?为什么没有内置一个迭代器呢?要回答这个问题,我们得从另外一个角度出发,了解一些基本的概念:
我们常常说遍历对象,但是简单来说,只会在两种层级上来对一个 JavaScript
对象进行遍历:
- 程序的层级 - 什么意思呢?在程序层级上,我们对一个对象进行迭代,是在迭代展示其结构的对象属性。 可能还不是很好理解,举个栗子:
Array.prototype.length
这个属性与对象的结构相关,但却不是它的数据。 - 数据的层级 - 意味着迭代数据结构并提取它的数据。举个栗子:我们在迭代一个数组的时候,迭代器是对于它的 每一个数据进行迭代,如果
array = [a, b, c, d]
那么迭代器访问到的是1, 2, 3, 4
。
明白了这个缘由, JavaScript
虽然不支持用 for of
来遍历对象,但是提供了一个 for in
方法来遍历所有非 Symbol
类型并且是可枚举的属性。
标准不支持,如果我们就是要用 for-of
来遍历对象呢?那我们可以任性的实现一个啊:
Object.prototype[Symbol.iterator] = function*() { for (const [key, value] of Object.entries(this)) { yield { key, value }; } };
for (const { key, value } of { a: 1, b: 2, c: 3 }) { console.log(key, value); }
不知道你有没有注意一个细节,在我们任性的实现一个 iterator
的代码中,我们用到了一个很奇怪的结构 function*() {}
,这个就是我们接下来要介绍的 Generator
Generators
看到这个名字觉得很厉害哈,但其实很简单,写一个 Generator
你只需要在函数名和 function
关键字中间加一个 *
号就可以了。至于里面的 yield
是什么,后面会说的。
talk is cheap , show me the code
,用一个例子,简单说一下概念。
我们现在定义了一个这样的 Generator
叫做 gen
function* gen() { yield 1; yield 2; yield 3; yield 4; }
我们只能看到,这里面有 4 个语句,那打印一下看看呗:
这里发现了一个熟悉的函数, next()
方法,我们把 gen
实例化一下,执行一下它的 next()
来看看结果:
还是熟悉的味道,那么到这里,我们已经知道, Generator
可以实例化出一个 iterator
,并且这个 yield
语句就是用来中断代码的执行的,也就是说,配合 next()
方法,每次只会执行一个 yield
语句。
多说一句,针对 Generator
本身,还有一个有意思的特性, yield
后面可以跟上另一个 Generator
并且他们会按照次序执行:
function* gen() { yield 1; yield* gen2(); return; } function* gen2() { yield 4; yield 5; } let iterator = gen(); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next());
结果很有意思不是吗?而且 return
会终结整个 Generator
,换句话说:写在 return
后面的 yield
不会执行。
Generator 有什么用?
Generator
有什么用? 聪明的同学可能已经猜到了,是的,它能够中断执行代码的特性,可以帮助我们来控制异步代码的执行顺序:
例如有两个异步的函数 A
和 B
, 并且 B
的参数是 A
的返回值,也就是说,如果 A
没有执行结束,我们不能执行 B
。
那这时候我们写一段伪代码:
function* effect() { const { param } = yield A(); const { result } = yield B(param); console.table(result); }
这时候我们如果需要得到 result
那么我们就需要:
const iterator = effect() iterator.next() iterator.next()
执行两次 next()
得到结果,看起来很傻不是吗?有没有好的办法呢?(废话,肯定有啊)
假设你在每次执行 A()
/ B()
的请求结束之后,都会自动执行 next()
方法呢?这不就解决了吗?
这样的库早就存在了,建议大家参考 co
的源码,当然你也可以通过阅读 这篇文章 来看看,到底 Generator
是怎么玩的。
最后
这里是 Dendoink ,奇舞周刊原创作者,掘金 [联合编辑 / 小册作者] 。
对于技术人而言:技 是单兵作战能力,术 则是运用能力的方法。得心应手,出神入化就是 艺 。在前端娱乐圈,我想成为一名出色的人民艺术家。扫码关注公众号 前端恶霸 我在这里等你:
以上所述就是小编给大家介绍的《[前端漫谈_1] 从 for of 聊到 Generator》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 前端智能漫谈:写给前端的 AI 白皮书
- [前端漫谈_3] 从 filter 聊到 Promise
- [前端漫谈] 一巴掌拍平Git中的各种概念
- [前端漫谈_2] 从 Dva 的 Effect 到 Generator + Promise 实现异步编程
- 漫谈 gRPC
- 漫谈gRPC
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
深入理解C++11
Michael Wong、IBM XL编译器中国开发团队 / 机械工业出版社 / 2013-6 / 69.00元
《深入理解C++11:C++11新特性解析与应用》内容简介:国内首本全面深入解读C++11新标准的专著,由C++标准委员会代表和IBM XL编译器中国开发团队共同撰写。不仅详细阐述了C++11标准的设计原则,而且系统地讲解了C++11新标准中的所有新语言特性、新标准库特性、对原有特性的改进,以及如何应用所有这些新特性。 《深入理解C++11:C++11新特性解析与应用》一共8章:第1章从设计......一起来看看 《深入理解C++11》 这本书的介绍吧!