Значение 'x' не является функцией или его возвращаемое значение не является повторяемой ошибкой

Я случайно увидел, что это вызывает ошибку в 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 замечание имеет смысл в своем контексте?


person Estus Flask    schedule 13.05.2020    source источник
comment
Чтобы воссоздать это сообщение об ошибке, попробуйте for (let val of (function () {})()) { } - вы не вызываете функцию в своем примере.   -  person jonrsharpe    schedule 13.05.2020
comment
Я подозреваю, что это мог быть остаток какого-то предложения, которое позволяло передавать функции генератора вместо генераторов где-то там, где сейчас принимаются только итераторы. @jonrsharpe Спасибо, это действительно вызывает ошибку.   -  person Estus Flask    schedule 13.05.2020
comment
Это как-то связано с использованием функций для создания примитивов. ЗАО ведет себя аналогичным образом. for (let val of Number(1)) {} и for (let val of Boolean(true)) {} выдают одну и ту же ошибку. for (let val of 1) {} и for (let val of true) {} нет.   -  person Ben Aston    schedule 13.05.2020
comment
Это экземпляры строки в V8. Однако я не могу найти ссылку на запись в таблице строк.   -  person Ben Aston    schedule 13.05.2020
comment
[...Symbol()] выдаст ту же ошибку TypeError, перейдя сюда, чтобы удалить мой ответ и продолжить обсуждение   -  person Robert Mennell    schedule 13.05.2020


Ответы (2)


Да, обе части сообщения об ошибке имеют смысл. В случае, если у вас есть под рукой, возвращаемое значение 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 циклов сделало недопустимо сложным создание подробных отчетов об ошибках, поэтому в комбинированном сообщении об ошибке просто упоминаются две возможные причины, по которым цикл не работал.

person jmrk    schedule 13.05.2020

Оператор for..of передает аргумент переменной через протокол итератора.

Протокол итератора определяет потребности метода @@ iterator для работы, поэтому, если функция, объект или класс не имеют реализованного Symbol.iterator / Symbol.asyncIterator, он выдаст эту ошибку.

В первом случае Symbol это константа, поэтому итерация невозможна. Во-вторых, значение превратилось в промежуточное значение, это означает, что виртуальная машина не может выполнить преобразование в итеративный тип (массивы, объекты, классы или функции с методом итератора), то есть не может быть выполнено чтобы получить результат из-за того, что for..of ожидает реализации метода @@ итератора.

Акцент сделан на том, что итератор - это функция, у которой есть метод @@ 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 или с объектами (доступ через ключ), функциями прототипа или просто генератором.

person lukaswilkeer    schedule 16.03.2021