最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - The meaning of "'x' is not a function or its return value is not iterable" error

programmeradmin0浏览0评论

I accidentally witnessed that this causes an error in V8 (Chrome, Node.js, etc):

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

TypeError: Symbol is not a function or its return value is not iterable

It appears that any other non-iterable value (including a function) causes another error:

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

TypeError: (intermediate value) is not iterable

As the reference states, the error is specific to Chrome:

TypeError: 'x' is not a function or its return value is not iterable (Chrome)

...

The value which is given as the right hand-side of for…of or as argument of a function such as Promise.all or TypedArray.from, is not an iterable object. An iterable can be a built-in iterable type such as Array, String or Map, a generator result, or an object implementing the iterable protocol.

It seems that none of listed things are expected to accept a function instead of iterable as an argument so it's unclear why the error puts emphasis on function type.

Is there any meaning to this error? Are there circumstances under which is not a function remark makes sense in its context?

I accidentally witnessed that this causes an error in V8 (Chrome, Node.js, etc):

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

TypeError: Symbol is not a function or its return value is not iterable

It appears that any other non-iterable value (including a function) causes another error:

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

TypeError: (intermediate value) is not iterable

As the reference states, the error is specific to Chrome:

TypeError: 'x' is not a function or its return value is not iterable (Chrome)

...

The value which is given as the right hand-side of for…of or as argument of a function such as Promise.all or TypedArray.from, is not an iterable object. An iterable can be a built-in iterable type such as Array, String or Map, a generator result, or an object implementing the iterable protocol.

It seems that none of listed things are expected to accept a function instead of iterable as an argument so it's unclear why the error puts emphasis on function type.

Is there any meaning to this error? Are there circumstances under which is not a function remark makes sense in its context?

Share Improve this question edited Jun 20, 2020 at 9:12 CommunityBot 11 silver badge asked May 13, 2020 at 10:57 Estus FlaskEstus Flask 223k78 gold badges469 silver badges605 bronze badges 5
  • 2 To recreate that error message, try for (let val of (function () {})()) { } - you're not calling the function in your example. – jonrsharpe Commented May 13, 2020 at 11:04
  • I suspect it could be a remnant of some proposal that allowed to pass generator functions instead of generators somewhere where iterators only are accepted now. @jonrsharpe Thanks, this triggers the error indeed. – Estus Flask Commented May 13, 2020 at 11:08
  • It's something to do with using functions to construct primitives. JSC behaves similarly. for (let val of Number(1)) {} and for (let val of Boolean(true)) {} emit the same error. for (let val of 1) {} and for (let val of true) {} do not. – Ben Aston Commented May 13, 2020 at 12:02
  • These are the instances of the string in V8. I cannot find the reference to the entry in the string table however. – Ben Aston Commented May 13, 2020 at 12:49
  • [...Symbol()] will throw the same TypeError, moving here to delete my answer and continue discussion – Robert Mennell Commented May 13, 2020 at 20:48
Add a comment  | 

2 Answers 2

Reset to default 6

Yes, there is meaning to both parts of the error message. In the case you have at hand, the return value of Symbol() is not iterable, so that's the second option. As an example for the first option, just take something that's not a function:

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

gives: Uncaught TypeError: NotAFunction is not a function or its return value is not iterable. In this case, clearly, NotAFunction is not a function ;-)

I don't know why there aren't two separate error messages for "it's not a function at all" and "it was a function and it's been called, but its return type wasn't iterable". Presumably something in the internal logic to implement for..of loops made it prohibitively complicated to have finer-grained error reporting -- so the combined error message simply mentions two possible reasons why the loop didn't work.

The for..of operator pass an argument to a variable trough the iterator protocol.

The iterator protocol specifies the needs of @@iterator method to work, so, if the function, object or a class doesn't have the Symbol.iterator/Symbol.asyncIterator implemented it will throw this error.

On the first case, the Symbol it's a constant, so it's not iterable. On the second, the value trowed it's a intermediate value, this means that the VM can't do a conversion to a iterable type(arrays, objects, classes or functions with the iterator method), that is, it can't be executed to get a result due to the fact that the for..of is expecting an implementation of the @@iterator method.

The emphasis comes due the fact that iterator is a function that have the @@iterator method. eg:


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

Printing:

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

The expected method of an for..of loop is a iterator function. So, the error message will empathize that is expecting a function.

To implement the method, you can do the same thing above, using ES6 classes, or with objects(accessing trough the key), prototype functions, or just a generator.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论