"'x'不是一个函数或其返回值不可迭代"错误的含义

19

我无意中目睹了这导致V8(Chrome、Node.js等)出错的原因:

for (let val of Symbol()) { /*...*/ }

类型错误:Symbol不是函数或其返回值不可迭代

似乎任何其他不可迭代的值(包括函数)都会导致另一个错误:

for (let val of function () { throw 'never called' }) { /*...*/ }

TypeError: (中间值) 不可迭代

正如参考文献所述,此错误仅适用于Chrome:

TypeError: 'x' 不是函数或其返回值不可迭代(Chrome)

...

作为for ... of的右侧或Promise.all或TypedArray.from等函数的参数给出的值不是可迭代对象。可迭代对象可以是内置可迭代类型,如Array、String或Map,生成器结果或实现可迭代协议的对象。

似乎没有预期在列出的任何东西中接受函数作为可迭代对象而不是参数,因此不清楚为什么错误强调函数类型。

这个错误有意义吗?在其上下文中是否存在“不是函数”备注有意义的情况?


2
要重新创建该错误消息,请尝试 for (let val of (function () {})()) { } - 在您的示例中没有调用该函数。 - jonrsharpe
我怀疑这可能是某个提案的残留物,该提案允许在现在只接受迭代器的地方传递生成器函数而不是生成器。@jonrsharpe 谢谢,这确实触发了错误。 - Estus Flask
这与使用函数构造原语有关。JSC的行为类似。for (let val of Number(1)) {}for (let val of Boolean(true)) {}会发出相同的错误。而for (let val of 1) {}for (let val of true) {}则不会。 - Ben Aston
这些是 V8 中字符串的实例。然而,我找不到字符串表中该条目的引用。 - Ben Aston
[...Symbol()] 会抛出相同的 TypeError,我在这里删除我的答案并继续讨论。 - Robert Mennell
2个回答

6

是的,这个错误信息的两部分都有意义。在你手头的这个情况下,Symbol() 的返回值不可迭代,所以这是第二个选项。举一个第一个选项的例子,只需要拿一个不是函数的东西就好了:

let NotAFunction = {};  // Or any other object.
for (let val of NotAFunction()) {}

出现以下错误:Uncaught TypeError: NotAFunction不是函数或其返回值不可迭代。在这种情况下,显然,NotAFunction不是一个函数;-)

我不知道为什么没有针对“根本不是函数”和“它是一个函数,但调用它的返回类型不可迭代”的两个单独的错误消息。可能是为了实现 for..of 循环的内部逻辑使得细分错误报告变得极为复杂 - 因此,合并的错误消息只提到了循环无法工作的两个可能原因。


3

for..of操作符通过迭代器协议将参数传递给变量。

迭代器协议规定了需要实现@@iterator方法才能工作,因此,如果函数、对象或类没有实现Symbol.iterator/Symbol.asyncIterator,它就会抛出此错误。

在第一种情况下,Symbol是一个常数,因此不可迭代。在第二种情况下,抛出的值是一个中间值,这意味着VM无法将其转换为可迭代类型(数组、对象、类或具有迭代器方法的函数),也就是说,由于for..of操作符期望有@@iterator方法的实现,它不能执行以获取结果。

突出显示这一点是因为迭代器是具有@@iterator方法的函数。例如:


const someIterator = {};
someIterator[Symbol.iterator] = function(names) {
    return {
        next() {
            this.index = 0;
            yield names[index];
            this.index = this.index++;
        }
    }
}

打印:

{[Symbol.iterator]: [Function (anonymous)]}

for..of循环的预期方法是一个迭代器函数,因此错误消息将会强调需要一个函数。

为了实现该方法,可以使用ES6类、对象(通过键访问)、原型函数或仅使用生成器完成相同的事情。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接