热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

从迭代器模式到迭代协议

迭代器模式迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而不需要暴露该对象的内部表示。迭代器分为内部迭代器和外部迭代器。内部迭代器只需一次初始调用&#x

迭代器模式

迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而不需要暴露该对象的内部表示。

迭代器分为内部迭代器和外部迭代器。内部迭代器只需一次初始调用,而外部迭代器必须显式地请求迭代下一个元素,这样我们就可以手动控制迭代过程。

实现一个内部迭代器:

Array.prototype.innerIterator = function(callback){for (let i = 0, len = this.length; i this[i], this[i], i)}
};
[1,2,3].innerIterator(function(item, index){console.log('item:', item, 'index:', index)
})
// item: 1 index: 0
// item: 2 index: 1
// item: 3 index: 2

实现一个外部迭代器:

Array.prototype.outerInterator &#61; function(){let index &#61; 0;return {next: () &#61;> {return index <this.length ?{value: this[index&#43;&#43;], done: false}:{value: undefined, done: true}}}
}
let iterator &#61; [1,2,3].outerInterator();for(let next; (next &#61; iterator.next()) && !next.done;) {console.log(&#39;item&#39;, next.value)
}
// item 1
// item 2
// item 3

迭代协议

了解了迭代器模式&#xff0c;再来看看 ES6 中补充的迭代协议。可迭代&#xff08;iterable&#xff09;协议和迭代器&#xff08;iterator&#xff09;协议。

可迭代协议&#xff1a;

一个可迭代对象&#xff08;或其原型上&#xff09;&#xff0c;必须有一个 Symbol.iterator 的属性&#xff0c;该属性所对应的值为返回一个对象的无參函数&#xff0c;被返回对象符合迭代器协议。当可迭代对象需要迭代时&#xff0c;调用该方法。

一些数据类型内置了 &#64;&#64;iterator 方法&#xff0c;有自己默认的迭代行为。&#xff08;String, Array, TypedArray, Map , Set 等都是内置可迭代对象&#xff0c; 因为它们的原型对象都有一个 &#64;&#64;iterator 方法.&#xff09;&#xff08;[Symbol.iterator]&#64;&#64;iterator 可以认为是一回事&#xff09;

let iterator &#61; (&#39;hi&#39;)[Symbol.iterator]()
var a &#61; iterator.next();
// a { value: &#39;h&#39;, done: false }

迭代器协议&#xff1a;

一个迭代器必须实现了 next() 方法&#xff0c;该方法是返回一个对象的无參函数。被返回的对象有两个必要的属性&#xff1a;done 和 value。

Array.prototype.Iteration &#61; function(){let index &#61; 0;return {[Symbol.iterator](){return this},next: () &#61;> {return index <this.length ?{value: this[index&#43;&#43;], done: false}:{value: undefined, done: true}}}
};
let Iteration &#61; [2, 3, 4].Iteration();
for(let value of Iteration) {console.log(&#39;value&#39;, value)
}
// value 2
// value 3
// value 4

不能发现&#xff0c;Iteration 同时满足可迭代协议和迭代协议。又因为是可迭代的&#xff0c;for...of 是可以直接使用&#xff0c;而且这个和外部迭代器十分相似。

一旦一种数据结构有了 &#64;&#64;iterator 方法后&#xff0c; 就认为是可迭代的。ES6 中许多新的方法就是基于此的 解构赋值扩展运算符yield*&#xff0c;还有 for..ofArray.from()等。

知道了以上知识&#xff0c;也就知道了为什么对象不可以直接使用 for...of 了。不过我们可以在对象原型上添加 &#64;&#64;iterator 方法&#xff0c;使之成为可迭代的。

Object.prototype.Iteration &#61; function(){let keys &#61; Object.keys(this), index &#61; 0;return{[Symbol.iterator](){return this},next: () &#61;> {let current &#61; index&#43;&#43;;return current value: [keys[current], this[keys[current]]], done: false}:{value: undefined, done: true};}}
}
let iterator &#61; {&#39;a&#39;: 1, &#39;b&#39;: 2, &#39;c&#39;: 3}.Iteration();for(let [key, value] of iterator) {console.log(&#39;key:&#39;, key, &#39;value:&#39;, value)
}
// key: a value: 1
// key: b value: 2
// key: c value: 3

生成器

像以上的的对象都是我们自己手动实现的&#xff0c;符合可迭代协议和迭代协议的对象。看起来很麻烦&#xff0c;还好这些工作已经有函数替我们做了&#xff0c;那就是生成器函数。

生成器函数是可以作为迭代器工厂的函数&#xff0c;当它被执行时会返回一个新的 Generator 对象&#xff0c;该对象符合可迭代协议和迭代器协议。

现在我们用生成器函数使得对象符合迭代协议&#xff1a;

Object.prototype.Iteration &#61; function *(){for(let [key, value] of Object.entries(this)){yield [key, value]}
}
for(let [key, value] of {&#39;a&#39;: 1, &#39;b&#39;: 2, &#39;c&#39;: 3}.Iteration()) {console.log(&#39;key:&#39;, key, &#39;value:&#39;, value)
}
// key: a value: 1
// key: b value: 2
// key: c value: 3

在这里生成器函数只是作为生产迭代器的工厂而已&#xff0c;其实它还是消息双向传递系统。也正是这些特性的存在&#xff0c;使得异步流程控制又向前迈了一大步。

转:https://juejin.im/post/5c92fce1f265da60f6730824



推荐阅读
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • Python SQLAlchemy库的使用方法详解
    本文详细介绍了Python中使用SQLAlchemy库的方法。首先对SQLAlchemy进行了简介,包括其定义、适用的数据库类型等。然后讨论了SQLAlchemy提供的两种主要使用模式,即SQL表达式语言和ORM。针对不同的需求,给出了选择哪种模式的建议。最后,介绍了连接数据库的方法,包括创建SQLAlchemy引擎和执行SQL语句的接口。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 解决.net项目中未注册“microsoft.ACE.oledb.12.0”提供程序的方法
    在开发.net项目中,通过microsoft.ACE.oledb读取excel文件信息时,报错“未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序”。本文提供了解决这个问题的方法,包括错误描述和代码示例。通过注册提供程序和修改连接字符串,可以成功读取excel文件信息。 ... [详细]
  • 本文介绍了一个React Native新手在尝试将数据发布到服务器时遇到的问题,以及他的React Native代码和服务器端代码。他使用fetch方法将数据发送到服务器,但无法在服务器端读取/获取发布的数据。 ... [详细]
author-avatar
fengzi199171
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有