集合迭代任务与iterator对象技术

223 阅读7分钟

======================== ES6新增iterator技术是被高度关注的技术,然,iterator确切是什么技术,解决何种编程任务(方便我们制作什么样的程序功能),又与 generator 技术(generator函数返一个iterator对象实例)是何关系,是一系列相关的重要的问题。

MDN文档开始劈头一句道出了iterator技术针对的任务:集合元素(项)的处理;并且强调这种任务非常的常见:

Processing each of the items in a collection is a very common operation.

EM:我以为任务非常常见是可信的,不然不会专门提出通用迭代操作的协议(借鉴别的语言),还开发generator作语法糖,简化编程。然,集合迭代能像CSS 页面布局那样是一种特别常见的任务吗?

集合迭代任务

要认识iterator技术,必先体会「集合迭代任务」的实质,和意义。

EM:利用统一迭代行为协议制作「可迭代对象」数据源,和利使用「可迭代对象」(通用for of等操作)制作有迭代结构的算法程序,是两个不同的编程任务;所以iterator技术要 分两个方面讲。

迭代操作

什么是迭代?迭代是针对集合数据一个种处理——逐个遍历访问集合所有数据项。集合类型常见是线性索引数组(indexed array)和带键标识的键值数组对象(associated array)。

为什么迭代

编程的任务[em]是构建具有计算结构的功能程序(模块),很多计算功能是基于集合数据结构的,要遍历集合数据项,例如数值数组求和,字符组转换等。简单说,很多计算功能(的算法实现)具有迭代结构。

EM: 某人的「任务」就是按自然律构建某种「存在」。

迭代实例

We have lots of places where we get a collection of items—consider document.querySelectorAll, which returns a NodeList, or Immutable.js 1 which has an Immutable.List object. We currently have no canonical API that we reach for to look at all the items in these collections. (此处需要进一步润色)

迭代技术

有了迭代计算结构的(任务)需求,就有相应的迭代技术。最早的迭代技术是所有程序员都熟悉的数组for循环(while循环原则也算,只是语法上没有for循环“甜”,也算是手动迭代技术,只是一种变相)。然而,for循环的弊病是明显——要手动管理迭代细节,噪音太多,很不“甜”。很多语言都发现传统「for循环」的不便,引入更易用更“甜”的自动迭代器工具——iterator。就JS而言,ES5引入了array.forEach方法,和for...in操作,然,forEach方法只适用于数组,for...in操作的功能也有局限。随着JS应用规模的增长,更自动更“甜”的迭代技术——iterable object——被引入ES6。

EM:“甜”是指语法糖果,越“甜”的语法越"适应"人脑思维特性,便于推理,提高编程效率。

集合迭代编程

整个「JS集合迭代编程」涉及两个层面,多个角度。 第一个层面,是使用可迭代数据源(iterable object ),进行具体的集合迭代功能的程序开发(特征是使用了for循环); 第二个层面,是根据迭代协议,制作可迭代数据源(特征是制作具有迭代操作API的对象);

角度则有抽象的迭代协议、迭代操作符和可迭代对象。

EM: 有趣的是,使用函数对象技术(轻便可作值传递)的「异步编程」也有多个层面和角度,例如事件模型、对象生命模型。

迭代协议

像JAVA这样的OO语言,通用的迭代操作行为可用一个抽象基类(interface)来统一定义,具体特定的迭代对象则对其进行派生。JS没有抽象基类,迭代行为由语言结构之外的语言标准来约定——迭代协议(iteration protocals)。迭代协议由「可迭代性」和「迭代操作」两部分组成。

developer.mozilla.org/en-US/docs/…

可迭代性

一个对象是否是标准的可迭代数据源,有一个唯一的属性标识——Symbol.iteratror,适用于迭代操作的安全标识。[Symbol.iteratror]是一个对象方法属性,返回一个实现了「迭代操作协议」的迭代器对象。

迭代器

协议规定了迭代操作的通用API行为:

有下一个值吗?是多少?

所以迭代器的结构很简单:一个next方法,方法返回一个结果{done,value},回答:

有下一值?(next),如果有(done),是多少(value)。

通过这个协议,「迭代数据源制作者」清楚如何制作 iterable object ,「迭代算法开发者」知道如何使用 iterable object (除了手动迭代,迭代操作符 for of等可自动代劳)。

可迭代对象

可迭代对象( iterable object )是「JS集合迭代编程」的核心,作为一种「计算对象」,迭代协议统一定义了它的通用结构和行为;数组(array)是原始的可迭代对象,ES6迭代技术将迭代操作泛化到一切对象。认识可迭代对象的一个难点,是区分「迭代器」和「可迭代对象」的关系。

迭代器和可迭代对象

迭代器协议是抽象的,它只规定了迭代API的形式涵义,而具体的迭代操作取决具体可迭代数据源逻辑;简单的说next方法返回下一个值,而这个值怎么来的,则是 iterable object A特定的。要制作一个自定义的可迭代对象(将一个普通对象转换为可迭代对象)就是为其制作特定的迭代器,不存独立的迭代器对象。

内建和自定的

  • String, Array, TypedArray, Map and Set are all built-in iterables

  • your iterable object (此处需要进一步润色)

迭代操作符

有了可迭代对象作数据源,我们就可迭代「使用它」,我们可手动迭代(调用next方法),然主要通过JS提供的自动迭操作符,包括for ..of 和...spread操作符,简化制作「具有迭代结构」的程序功能。

通过以上简精的分析,所谓「迭代技术」不是一单一的新工具/技术,不是单一的新型铁锤,也不像是新的CSS布局技术(flexbox)那样单一。「迭代技术」可涵盖多个方面。看这个图:

开发者集合迭代编程的「任务」只是制作「集合迭代结构的程序」,使用的「技术」是一个易用的「可迭代对象」和JS提供的自动迭代操作符(例如for of)。

除以上外,JS还提供一些内建的「可迭代对象」,和迭代协议给开发者转变角色,自行开发「可迭代对象」。从这个角度看,JS提供的不(仅)是一个现成的铁锤(当然内建的可迭代对象算是现在的),而是一张设计图。开发者除了使用铁锤,还可以自己煅造特制铁锤。

Generator 自生函数对象

迭代器/可迭代对象本身也是有结构的,也是一种「程序」,有自己的「编程任务」,也需要「技术」。上面提到的迭代器制作,是手动,不使用任何中间技术/工具。由于手动被认为过于繁琐,需要一些工具,Generator函数就是这样的工具/技术。

很多语言传统「使用for循环」制作集合遍历计算结构,都发现它的不便,引入更易用的自动迭代器 Many programming languages have shifted from iterating over data with for loops, which requires initializing variables to track position in a collection, to using itera- tor objects that programmatically return the next item in a collection. Iterators make working with collections of data easier,

What

其实不存在一种iterator对象,只有一个组制作迭代行为的协义。开发者根据这组行为协议制作「可迭代的对象」,从而产出一个新的语法糖果(for of ...) (另一个)开发者则利用语法糖果方便制作「有集合迭代处理 」计算功能程序(模块)

iterated structure program