15

我无意中看到这会导致 V8(Chrome、Node.js 等)出现错误:

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

TypeError:符号不是函数或其返回值不可迭代

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

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

TypeError:(中间值)不可迭代

正如参考资料所述,该错误特定于 Chrome:

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

...

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

似乎所有列出的东西都不应该接受函数而不是可迭代作为参数,因此不清楚为什么错误强调函数类型。

这个错误有什么意义吗?在某些情况下,is not a function评论在其上下文中是有意义的吗?

4

2 回答 2

5

是的,错误消息的两个部分都有意义。在你手头的情况下,返回值Symbol()是不可迭代的,所以这是第二个选项。作为第一个选项的示例,只需使用不是函数的东西:

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

给出:Uncaught TypeError: NotAFunction is not a function or its return value is not iterable。在这种情况下,显然NotAFunction不是函数;-)

我不知道为什么“它根本不是一个函数”和“它是一个函数并且它被调用,但它的返回类型不可迭代”没有两个单独的错误消息。据推测,实现for..of循环的内部逻辑中的某些东西使得拥有更细粒度的错误报告变得异常复杂——因此组合的错误消息只是提到了循环不起作用的两个可能原因。

于 2020-05-13T17:39:38.297 回答
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 类或对象(通过键访问)、原型函数或仅使用生成器来执行上述相同的操作。

于 2021-03-16T11:35:29.837 回答