JavaScript 中是否有任何已知的技巧可以在不触发迭代的情况下区分
Iterator
和 AsyncIterator
之间的区别?
我正在尝试实现以下类型检查器:
function isAsyncIterator<T>(i: Iterator<T> | AsyncIterator<T>): boolean {
// returns:
// - true, if i is an asycnronous iterator
// - false, if i is a syncronous iterator
}
我知道调用
next
会告诉我们这一点,但当我无法触发迭代时我需要它。
此外,即使我在 TypeScript 中给出了示例,我也需要在运行时严格检查它。
更新
后来发现我们唯一可以做到的方法如下:
sync
标志,并且将包装根据请求返回的第一个值。这是不可能的。 迭代器是由协议定义的,而不是由有形属性定义的,因此由于停止问题,如果不实际迭代一个对象,就无法确定它是否是迭代器。另请参阅类似的问题Javascript 可迭代的技术定义是什么以及如何测试它?.
但是,有一些很好的启发式方法可以检测大多数行为良好的迭代器实现和所有内置迭代器:
迭代器通常是可迭代的(否则它们不能在
for … of
循环中使用,从而限制了它们的用处),并且会为此委托给自己。所以
function isIterator(obj) {
if (Object(obj) !== obj) return false;
const method = obj[Symbol.iterator];
if (typeof method != 'function') return false;
const iter = method.call(obj);
return iter === obj;
}
function isAsyncIterator(obj) {
if (Object(obj) !== obj) return false;
const method = obj[Symbol.asyncIterator];
if (typeof method != 'function') return false;
const aIter = method.call(obj);
return aIter === obj;
}
迭代器继承自内置
%IteratorPrototype%
。在迭代器助手提案将引入全局Iterator
构造函数之前,这些对象的访问和测试有点麻烦,但仍然是可能的。
const GeneratorPrototype = Object.getPrototypeOf(function*() {}).prototype;
const IteratorPrototype = Object.getPrototypeOf(GeneratorPrototype);
const AsyncGeneratorPrototype = Object.getPrototypeOf(async function*() {}).prototype;
const AsyncIteratorPrototype = Object.getPrototypeOf(AsyncGeneratorPrototype);
function isIterator(obj) {
return IteratorPrototype.isPrototypeOf(obj);
}
function isAsyncIterator(obj) {
return AsyncIteratorPrototype.isPrototypeOf(obj);
}
(当然,就像任何
instanceof
检查一样,这不适用于其他领域的对象,这就是为什么我会推荐第一种方法)