Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

for...of loop produces "Uncaught TypeError: myObject[Symbol.iterator] is not a function" error #84

Closed
andfaulkner opened this issue Jul 8, 2015 · 16 comments

Comments

@andfaulkner
Copy link

The transpiler currently seems to be unable to handle for...of loops. Using them causes Uncaught TypeError: myObject[Symbol.iterator] is not a function

For example, the following code:

    var myObject = {
        "key1": "value1",
        "key2": "value2",
        "key3": "value3",
        "fn1": function(){ 
            console.log("fn1 ran!"); 
        },
        "fn2": function(param){
            console.log(param); 
        },
        "number1": 4
    }

    for (let item of myObject){
        console.log(item);
    }

...which gets converted into:

    var myObject = {
        "key1": "value1",
        "key2": "value2",
        "key3": "value3",
        "fn1": function fn1() {
            console.log("fn1 ran!");
        },
        "fn2": function fn2(param) {
            console.log(param);
        },
        "number1": 4
    };

    var _iteratorNormalCompletion = true;
    var _didIteratorError = false;
    var _iteratorError = undefined;

    try {
        for (var _iterator = myObject[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
            var item = _step.value;
            console.log(item);
        }
    } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
    } finally {
        try {
            if (!_iteratorNormalCompletion && _iterator["return"]) {
                _iterator["return"]();
            }
        } finally {
            if (_didIteratorError) {
                throw _iteratorError;
            }
        }
    }

...produces the following error when run:

 'Uncaught TypeError: someObj[Symbol.iterator] is not a function'
 utilMainModule  @                               app.js:28208
 (anonymous function)  @                   app.js:28316
 _curFld    @                                         app.js:28317
 __webpack_require__   @                   app.js:30
 main    @                                        app.js:523
 navdrawerModule   @                          app.js:26701
 (anonymous function)   @                  app.js:26873
 moduleNm    @                                    app.js:26875
 __webpack_require__    @                  app.js:30
                   [.............(more items)..........]
(anonymous function) @                     app.js:10
webpackUniversalModuleDefinition @ app.js:9
(anonymous function) @                     app.js:53

This occurs in both Chrome and Firefox. I've tried it in several different places in my codebase, with the same result every time.

@Couto
Copy link
Member

Couto commented Jul 8, 2015

Have you imported the polyfill?

@andfaulkner
Copy link
Author

I'm using the es6-shim node module.

However, I'm not using the Babel-specific module - I'll give that a try.

@Couto
Copy link
Member

Couto commented Jul 8, 2015

I haven't tried babel with other shims, but to use for of you'll have to, at least, shim the Simbol and prototype[Symbol.iterator]

@andfaulkner
Copy link
Author

Just installed it. I ensured babel was explicitly installed in my node_modules (npm install babel --save-dev and npm install babel-core --save-dev, then added require("babel/polyfill"); to the top of my app's javascript entry point. Same issue.

I'm going to try explicitly including it via a <script> tag.

@andfaulkner
Copy link
Author

Tried including it in the <head> section of my html entry point - it still produced the same error. It's definitely loading it, and it does so prior to everything else (I added a single console log to browser-polyfill.js to confirm this).

I also tried excluding my other polyfill library, but this also didn't work.

Also, Symbol and Symbol.iterator are definitely polyfilled - I can run them outside the context of a for...of loop with no problems.

Any other thoughts?

@zloirock
Copy link
Member

zloirock commented Jul 9, 2015

es6-shim support Symbol.iterator only with native Symbol and causes conflicts in your case. Use babel/polyfill / core-js instead of es6-shim.

@andfaulkner
Copy link
Author

I'd already removed es6-shim and included babel/polyfill - it's still throwing the same error.

@zloirock
Copy link
Member

zloirock commented Jul 9, 2015

@andfaulkner stop... I didn't saw your code. Plain objects are not iterable. You can use something like

for (let [key, value] of Object.entries(myObject)){
  console.log(key, value);
}

or add custom iterator to your object.

@andfaulkner
Copy link
Author

Aha! Success!

Thanks a trillion, I mean it :)

@ShadSterling
Copy link

What? Plain objects are not iterable? Why?

budparr pushed a commit to gohugoio/gohugoioTheme that referenced this issue Jul 17, 2017
Error: Uncaught TypeError: myObject[Symbol.iterator] is not a function

Found a fix for the issue here: babel/babel-loader#84

Fixes #84

Signed-off-by: budparr <budparr@gmail.com>
@nabilfreeman
Copy link

nabilfreeman commented Aug 3, 2017

@Polyergic https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of

Only arrays etc. can be used with for ... of.

To iterate over the keys in an object, you need to use for ... in.

To iterate over the values, you can do for value of Object.values(my_obj) which will return an array of values from the object.

(I just learnt this)

@therealwolf42
Copy link

@nabilfreeman When I use for ... in - I get

TS1005: 'of' expected.

for await (let c of content){
console.log(content)
}

any idea?

@danez
Copy link
Member

danez commented Oct 9, 2017

@therealwolf42 TS1005 looks very much like typescript and not babel.

@loganfsmyth
Copy link
Member

Only arrays etc. can be used with

The first bit there seems a bit misleading Any iterable object can be used with for...of. Arrays just happen to be one type of iterable object.

Generally the way to iterate an object's keys these days would be

Object.keys(obj).forEach(key => {
    const value = obj[key];
    // ...
});

or if you polyfill Object.entries then

for (const [key, value] of Object.entries(obj)) {
    // ...
}

@ShadSterling
Copy link

ShadSterling commented Oct 9, 2017

The real problem here is that when you try to iterate over a non-iterable object, you get a bad error message. Different implementations give different error messages, but every one I've seen has been bad.

for...of iterates over values (not keys); for an Array the keys are whole numbers starting with 0, and are often unimportant, so iterating over the values makes sense. While it sometimes make sense to iterate over the values that correspond to the (not generally numerical) keys of a plain object, the for...of construct does not allow that, so it fails with an (incomprehensible) error message.

for...in iterates over keys (not values); for an Array the keys are whole numbers starting with 0, so iterating over the keys rarely makes sense. But for..in does support iterating over the keys of a plain object, which makes it all the more confusing that for...of does not.

This is not a bug in any implementation; if it's a bug in anything, it's in the language spec.

The workaround I've taken to using is

for( key in var ) {
    value = var[key];
    // ... do stuff with value
}

@fardous80
Copy link

I was having the same problem iterating over FileReader items, finally solved it using Array.from

let files = e.target.files || e.dataTransfer.files;

Array.from(files).forEach(file => {
 // do whatever
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants