在 ES6 中,引入了迭代协议,可以使用 for...of
循环迭代出可迭代对象中的每个值。再通过增强的迭代器协议,可以自定义迭代出的数据结构,但是需要实现 next()
方法。在 ES9 中,可以使用 Symbol 对象来定义迭代器,从而完全重写类库的迭代器功能。
Symbol 对象
Symbol 是一种原始数据类型,它可以用来创建唯一的标识符,不与其他标识符混淆。在对象上通过使用 Symbol 对象作为属性名,可以创建一种私有属性,防止属性与其他属性冲突。
let id = Symbol('id'); let user = { name: 'John', [id]: 123 }; console.log( user[id] ); // 123
在上面的例子中,我们创建了一个 id
的 Symbol 对象,并将它赋值给 user
对象的一个属性。我们可以通过方括号标识符属性访问器来访问这个属性。
Symbol.iterator
在 ES6 中,迭代器协议通过 Symbol.iterator
属性来实现。每个对象都可以返回一个迭代器对象,该对象有一个 next()
方法,用于迭代每个对象的值。
在 ES9 中,我们可以使用 Symbol 对象重写迭代器协议。我们将使用 Symbol.asyncIterator
,该属性与 Symbol.iterator
用法相同,只是它的返回值是一个异步迭代器。
-- -------------------- ---- ------- ----- ----- - -------- -- --- --------------- -- ------------------- ----------- ----- ------------------ - -- -- - --- ----- - -- ------ - ------------------------ - ------ - ----- ------ - ----- ------------ -------- ------ - ----- ------ ------ ----- -- - -- - -- -- ----- ------------ - --------------------- ------ -- -- - --- ----- ---- ----- -- ------------- - -- ------ - --- ------ ------------------- - -----
在上面的例子中,我们创建了一个异步计数器对象,其中的 Symbol.asyncIterator
方法返回一个包含 next()
方法的对象,用于异步迭代计数器的值。在 next()
方法中,我们每隔一秒钟增加计数器的值,并返回一个结果对象,其中 done
属性表示是否已完成迭代,value
属性是当前值。
最后,我们使用 for ... await ... of
语法异步迭代计数器对象的值,并显示前 10 个计数器。
应用
使用 Symbol 对象重写迭代器协议的主要优势之一是为重写现有的类库提供了更好的方式,而无需更改类库本身的代码。我们可以使用 Symbol 对象将原始迭代器协议替换为类库的新迭代器。
例如,在 Node.js 中,可以使用 Symbol.asyncIterator
和 Symbol.iterator
来为 stream.Readable
实现基于 Promise 的迭代器和异步迭代器。
-- -------------------- ---- ------- ----- - -------- - - ------------------ ----- ----------------- - ----- --------- ---------------- - ----- ------ - --------------------------- ----- ------ - ----- - ----- ----- - - ----- -------------- -- ------ ------ ----- ------ - -- ----- -------------- - -------------------- ---------- ----- ------------- - ---------------------------------- ------ -- -- - --- ----- ---- ----- -- -------------- - ------------------------------ - -----
在上面的示例中,我们创建了一个 makeAsyncIterable
函数,它使用 stream.Readable
创建一个基于 Promise 的迭代器。我们首先获取 Readable
流的 getReader()
,并在无限循环中等待每个块,然后 yield 该块,并在读取完所有块后退出循环。最后,我们使用 for ... await ... of
语句,异步迭代数据流,并 log 每个块的内容。
结论
Symbol 对象提供了一种更好的方式来重写、扩展和自定义现有的迭代器协议,从而更好地适应类库的需求。由于迭代器协议在许多领域都被使用,因此 Symbol 对象的这种优势为开发人员提供了一个强大的工具,可以处理许多可能需要自定义的应用程序。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/676d3e7e82fcee791c660752