JavaScript支持将函数作为一等数据,因此您可以轻松地使用抽象来创建自己的工具。在下面的示例中,我们使用我们自己创造的抽象
Yield
和
Return
来发明我们自己的
持久化(不可变)迭代器。使用
记忆化技术可以避免重复计算迭代器的下一个值。
我们的持久化迭代器几乎与JS本机迭代器表现相同,只是它们是不可变的!
done
、
value
和
next
属性应该感觉很熟悉。
const Memo = (f, memo) => () =>
memo === undefined
? (memo = f (), memo)
: memo
const Yield = (value, next = Return) =>
({ done: false, value, next: Memo (next) })
const Return = value =>
({ done: true, value })
const Range = (min = 0, max = Infinity) =>
min > max
? Return ()
: Yield (min, () => Range (min + 1, max))
const state0 =
Range (0, 2)
console.log (state0.done)
console.log (state0.value)
console.log (state0.value)
const state1 =
state0.next ()
console.log (state1.done)
console.log (state1.value)
console.log (state1.value)
const state2 =
state1.next ()
console.log (state2.done)
console.log (state2.value)
console.log (state2.value)
const state3 =
state2.next ()
console.log (state3.done)
但是你不应该使用赋值来遍历迭代器,递归才是我们需要的
const MappedIterator = (f, it = Return ()) =>
it.done
? Return ()
: Yield (f (it.value), () => MappedIterator (f, it.next ()))
const Generator = function* (it = Return ())
{
while (it.done === false)
(yield it.value, it = it.next ())
return it.value
}
const square = x =>
x * x
Array.from (Generator (MappedIterator (square, Range (0, 10))))
当然,由于迭代器是持久的,我们可以多次遍历同一迭代器。
const ConcatIterator = (x = Return (), y = Return ()) =>
x.done
? y
: Yield (x.value, () => ConcatIterator (x.next (), y))
const it =
MappedIterator (square, Range (1, 3))
Array.from (Generator (it)) // => [ 1, 4, 9 ]
Array.from (Generator (ConcatIterator (it, it))) // => [ 1, 4, 9, 1, 4, 9 ]
这是完整的代码演示。
const Memo = (f, memo) => () =>
memo === undefined
? (memo = f (), memo)
: memo
const Yield = (value, next = Return) =>
({ done: false, value, next: Memo (next) })
const Return = value =>
({ done: true, value })
const Range = (min = 0, max = Infinity) =>
min > max
? Return ()
: Yield (min, () => Range (min + 1, max))
const MappedIterator = (f, it = Return ()) =>
it.done
? Return ()
: Yield (f (it.value), () => MappedIterator (f, it.next ()))
const ConcatIterator = (x = Return (), y = Return ()) =>
x.done
? y
: Yield (x.value, () => ConcatIterator (x.next (), y))
const Generator = function* (it = Return ())
{
while (it.done === false)
(yield it.value, it = it.next ())
return it.value
}
const it =
MappedIterator (x => x * x, Range (1, 3))
console.log (Array.from (Generator (it)))
console.log (Array.from (Generator (ConcatIterator (it, it))))
var other = [...iterator]
。 - Aluan Haddad