Jav*_*ser 3 javascript iterator ecmascript-6
我正在实现一个双向链表作为编程练习的一部分,并且我希望允许开发人员使用符号向前和向后迭代其节点for...in。
最基本的数据结构如下所示:
class DoublyLinkedList {
constructor(data) {
if (data) {
this.head = new DoublyLinkedListNode(data)
} else {
this.head = null
}
}
append = (data) => {
if (!this.head) {
this.prepend(data)
} else {
const newTail = new DoublyLinkedListNode(data)
let current = this.head
while(current.next) {
current = current.next
}
current.next = newTail
newTail.prev = current
}
}
}
Run Code Online (Sandbox Code Playgroud)
接下来我添加了生成器函数:
*values() {
let current = this.head
while (current) {
yield current.data;
current = current.next;
}
}
*valuesBackward() {
let currentForwards = this.head
while (currentForwards.next) {
currentForwards = currentForwards.next
}
const tail = currentForwards
let currentBackwards = tail
while (currentBackwards) {
yield currentBackwards.data
currentBackwards = currentBackwards.prev
}
}
Run Code Online (Sandbox Code Playgroud)
我可以添加一个向前迭代器,并将以下内容添加到类中:
[Symbol.iterator]() { return this.values()}
Run Code Online (Sandbox Code Playgroud)
我尝试将以下两项添加到班级中:
iterateForward = () => [Symbol.iterator] = () => this.valuesBackward()
iterateBackward = () => [Symbol.iterator] = () => this.valuesBackward()
Run Code Online (Sandbox Code Playgroud)
然后尝试迭代使用,for (node in list.iterateForward())但失败并出现错误TypeError: undefined is not a function。
我想看看代码是有意义的,所以接下来我尝试了:
iterateForward = () => {
const vals = this.values()
const it = {
[Symbol.iterator]() {
return vals()
}
}
return it
}
Run Code Online (Sandbox Code Playgroud)
这没有错误,但迭代不起作用 - 迭代器运行了零次。
我在这里缺少什么?有可能实现我想要的吗?
这些东西经常让我感到困惑,所以这里有一个我们都可以参考的摘要。
这是背景
Aniterable是一个具有该[Symbol.iterator]属性的对象,当您将该属性作为函数调用时,它会返回一个迭代器对象。
迭代器对象有一个属性.next(),每次调用该函数时,它都会返回具有预期属性的对象{value: x, done: false}。迭代器对象通常将迭代的状态保存在这个单独的对象中(因此迭代器可以彼此独立)。
因此,为了支持多个迭代器,您可以创建多个方法,其中每个方法返回一个不同的可迭代对象,每个方法都有自己的迭代器对象[Symbol.iterator],在调用时返回不同的迭代器对象。
因此,回顾一下,您:
[Symbol.iterator]可迭代对象是一个具有属性并可以访问原始对象数据的对象。[Symbol.iterator],您将获得一个迭代器对象。.next()方法,可以获取序列中的每个项目,并且通过{value: x, done: false}每次调用时返回一个这样的对象来实现这一点.next()。您可以跳过第 1 步,只让您的核心对象拥有[Symbol.iterator]该属性。这基本上成为您的默认迭代。如果你这样做:
for (let x of myObj) {
console.log(x);
}
Run Code Online (Sandbox Code Playgroud)
它将访问myObj[Symbol.iterator]()并获取迭代器。但是,如果您希望有不止一种方法来迭代您的集合,那么您可以创建单独的函数,每个函数返回自己的可迭代对象(它们自己的对象,具有自己的[Symbol.iterator]属性)。
在数组中,您有.entries()和.values()作为返回不同迭代的两个方法的示例,这两个方法产生不同的迭代器。
let x = ['a', 'b', 'c'];
for (let v of x.values()) {
console.log(v);
}
Run Code Online (Sandbox Code Playgroud)
这给出了输出:
'a'
'b'
'c'
Run Code Online (Sandbox Code Playgroud)
或者,对于.entries():
let x = ['a', 'b', 'c'];
for (let v of x.entries()) {
console.log(v);
}
[0, "a"]
[1, "b"]
[2, "c"]
Run Code Online (Sandbox Code Playgroud)
因此,每个 和.values()都会.entries()返回一个不同的对象,每个对象都有不同的对象[Symbol.iterator],当作为函数调用时,会为其唯一序列返回不同的迭代器函数。
并且,在数组的情况下,.values()返回一个函数,当调用该函数时,它会为您提供与直接迭代数组完全相同的迭代器(例如[Symbol.iterator]数组本身的属性)。
现在,针对您的具体情况
您想要创建两个方法,假设.forward()每个.backward()方法都创建一个具有属性的对象[Symbol.iterator],该属性是一个函数,在调用时返回其唯一的迭代器对象。
因此,obj.forward()将返回一个具有属性的对象[Symbol.iterator],该属性是一个函数,在调用时返回具有适当的.next()向前迭代属性和适当的起始状态的迭代器对象。
因此,obj.backward()将返回一个具有属性的对象[Symbol.iterator],该属性是一个函数,在调用时返回具有适当属性的迭代器对象.next()以向后迭代和适当的起始状态。
这是使用数组的示例:
for (let x of myObj) {
console.log(x);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
942 次 |
| 最近记录: |