• 售前

  • 售后

热门帖子
入门百科

ES6的循环与可迭代对象示例详解

[复制链接]
七七小嗳 显示全部楼层 发表于 2021-10-25 20:11:24 |阅读模式 打印 上一主题 下一主题
本文将研究 ES6 的 for ... of 循环。
旧方法


在过去,有两种方法可以遍历 javascript。
起首是经典的 for i 循环,它使你可以遍历数组或可索引的且有 length 属性的任何对象。
  1. for(i=0;i<things.length;i++) {
  2. var thing = things[i]
  3. /* ... */
  4. }
复制代码
其次是 for ... in 循环,用于循环一个对象的键/值对。
  1. for(key in things) {
  2. if(!thing.hasOwnProperty(key)) { continue; }
  3. var thing = things[key]
  4. /* ... */
  5. }
复制代码
for ... in 循环通常被视作旁白,因为它循环了对象的每一个可罗列属性[1]。这包括原型链中父对象的属性,以及被分配为方法的以是属性。换句话说,它遍历了一些人们可能想不到的东西。使用 for ... in 通常意味着循环块中有很多掩护子句,以制止出现不必要的属性。
早期的 javascript 通过库办理了这个题目。很多 JavaScript 库(比方:Prototype.js,jQuery,lodash 等)都有类似 each 或 foreach 这样的工具方法或函数,可让你无需 for i 或 for ... in 循环去遍历对象和数组。
for ... of 循环是 ES6 试图不消第三方库去办理此中一些题目的方式。
for … of


for ... of 循环
  1. for(const thing of things) {
  2. /* ... */
  3. }
复制代码
它将遍历一个可迭代(iterable)对象。
可迭代对象是定义了 @@ iterator 方法的对象,而且 @@iterator 方法返回一个实现了迭代器协议的对象,或者该方法是生成器函数。
在这句话中你必要理解很多东西:
      
  • 可迭代的对象  
  • @@iterator方法( @@是什么意思?)  
  • 迭代器协议(这里的协议是什么意思?)  
  • 等等,迭代(iterable)和迭代器(iterator)不是一回事?  
  • 别的,天生器函数又是什么鬼?
下面逐个办理这些疑问。
内置 Iterable


起首,javascript 对象中的一些内置对象自然的可以迭代,好比最容易想到的就是数组对象。可以像下面的代码中一样在 for ... of 循环中使用数组:
  1. const foo = [
  2. 'apples','oranges','pears'
  3. ]
  4. for(const thing of foo) {
  5. console.log(thing)
  6. }
复制代码
输出结果是数组中的全部元素。
  1. apples
  2. oranges
  3. pears
复制代码
另有数组的 entries 方法,它返回一个可迭代对象。这个可迭代对象在每次循环中返回键和值。比方下面的代码:
  1. const foo = [
  2. 'apples','oranges','pears'
  3. ]
  4. for(const thing of foo.entries()) {
  5. console.log(thing)
  6. }
复制代码
将输出以下内容
  1. [ 0, 'apples' ]
  2. [ 1, 'oranges' ]
  3. [ 2, 'pears' ]
复制代码
当用下面的语法时,entries 方法会更有效
  1. const foo = [
  2. 'apples','oranges','pears'
  3. ]
  4. for(const [key, value] of foo.entries()) {
  5. console.log(key,':',value)
  6. }
复制代码
在 for 循环中声明白两个变量:一个用于返回数组的第一项(值的键或索引),另一个用于第二项(该索引实际对应的值)。
一个平凡的 javascript 对象是不可迭代的。如果你实行下面这段代码:
  1. // 无法正常执行
  2. const foo = {
  3. 'apples':'oranges',
  4. 'pears':'prunes'
  5. }
  6. for(const [key, value] of foo) {
  7. console.log(key,':',value)
  8. }
复制代码
会得到一个错误
  1. $ node test.js
  2. /path/to/test.js:6
  3. for(const [key, value] of foo) {
  4. TypeError: foo is not iterable
复制代码
然而全局 Object 对象的静态 entries 方法接受一个平凡对象作为参数,并返回一个可迭代对象。就像这样的程序:
  1. const foo = {
  2. 'apples':'oranges',
  3. 'pears':'prunes'
  4. }
  5. for(const [key, value] of Object.entries(foo)) {
  6. console.log(key,':',value)
  7. }
复制代码
能够得到你渴望的输出:
  1. $ node test.js
  2. apples : oranges
  3. pears : prunes
复制代码
创建本身的 Iterable


如果你想创建本身的可迭代对象,则必要耗费更多的时间。你会记得前面说过:
  1. 可迭代对象是定义了 @@ iterator 方法的对象,而且 @@iterator 方法返回一个实现了迭代器协议的对象,或者该方法是生成器函数。
复制代码
搞懂这些内容的最简朴方法就是一步一步的去创建可迭代对象。起首,我们必要一个实现 @@iterator 方法的对象。 @@ 表现法有点误导性,我们真正  要做的是用预定义的 Symbol.iterator 符号定义方法。
如果用迭代器方法定义对象并实行遍历:
  1. const foo = {
  2. [Symbol.iterator]: function() {
  3. }
  4. }
  5. for(const [key, value] of foo) {
  6. console.log(key, value)
  7. }
复制代码
得到一个新错误:
  1. for(const [key, value] of foo) {
  2.                           ^
  3. TypeError: Result of the Symbol.iterator method is not an object
复制代码
这是 javascript 告诉我们它在试图调用 Symbol.iterator 方法,但是调用的结果不是对象。
为了消除这个错误,必要用迭代器方法来返回实现了迭代器协议的对象。这意味着迭代器方法必要返回一个有 next 键的对象,而 next 键是一个函数。
  1. const foo = {
  2. [Symbol.iterator]: function() {
  3. return {
  4. next: function() {
  5. }
  6. }
  7. }
  8. }
  9. for(const [key, value] of foo) {
  10. console.log(key, value)
  11. }
复制代码
如果运行上面的代码,则会出现新错误。
  1. for(const [key, value] of foo) {
  2.                      ^
  3. TypeError: Iterator result undefined is not an object
复制代码
这次 javascript 告诉我们它试图调用 Symbol.iterator 方法,而该对象的确是一个对象,并且实现了 next 方法,但是 next 的返回值不是 javascript 预期的对象。
next 函数必要返回有特定格式的对象——有 value 和 done 这两个键。
  1. next: function() {
  2. //...
  3. return {
  4. done: false,
  5. value: 'next value'
  6. }
  7. }
复制代码
done 键是可选的。如果值为 true(表现迭代器已完成迭代),则阐明迭代已竣事。
如果 done 为 false 或不存在,则必要 value 键。 value 键是通过循环此应该返回的值。
以是在代码中放入另一个程序,它带有一个简朴的迭代器,该迭代器返回前十个偶数。
  1. class First20Evens {
  2. constructor() {
  3. this.currentValue = 0
  4. }
  5. [Symbol.iterator]( "Symbol.iterator") {
  6. return {
  7. next: (function() {
  8. this.currentValue+=2
  9. if(this.currentValue > 20) {
  10.   return {done:true}
  11. }
  12. return {
  13.   value:this.currentValue
  14. }
  15. }).bind(this)
  16. }
  17. }
  18. }
  19. const foo = new First20Evens;
  20. for(const value of foo) {
  21. console.log(value)
  22. }
复制代码
天生器


手动去构建实现迭代器协议的对象不是唯一的选择。天生器对象(由天生器函数返回)也实现了迭代器协议。上面的例子用天生器构建的话看起来像这样:
  1. class First20Evens {
  2. constructor() {
  3. this.currentValue = 0
  4. }
  5. [Symbol.iterator]( "Symbol.iterator") {
  6. return function*() {
  7. for(let i=1;i<=10;i++) {
  8. if(i % 2 === 0) {
  9.   yield i
  10. }
  11. }
  12. }()
  13. }
  14. }
  15. const foo = new First20Evens;
  16. for(const item of foo) {
  17. console.log(item)
  18. }
复制代码
本文不会过多地介绍天生器,如果你必要入门的话可以看这篇文章。本日的重要劳绩是,我们可以使本身的 Symbol.iterator 方法返回一个天生器对象,并且该天生器对象能够在 for ... of 循环中“正常工作”。 “正常工作”是指循环能够一连的在天生器上调用 next,直到天生器停止 yield 值为止。
  1. $ node sample-program.js
  2. 2
  3. 4
  4. 6
  5. 8
  6. 10
复制代码
参考资料
对象的每个可罗列属性: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in
总结

到此这篇关于ES6的循环与可迭代对象的文章就介绍到这了,更多干系ES6循环与可迭代对象内容请搜刮草根技术分享以前的文章或继续浏览下面的干系文章渴望大家以后多多支持草根技术分享!

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作