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.
Have you imported the polyfill?
I'm using the es6-shim node module.
However, I'm not using the Babel-specific module - I'll give that a try.
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]
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.
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?
es6-shim support Symbol.iterator only with native Symbol and causes conflicts in your case. Use babel/polyfill / core-js instead of es6-shim.
I'd already removed es6-shim and included babel/polyfill - it's still throwing the same error.
@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.
Aha! Success!
Thanks a trillion, I mean it :)
What? Plain objects are not iterable? Why?
@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)
@nabilfreeman When I use for ... in - I get
TS1005: 'of' expected.
for await (let c of content){
console.log(content)
}
any idea?
@therealwolf42 TS1005 looks very much like typescript and not babel.
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)) {
// ...
}
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
}
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
})
Most helpful comment
@andfaulkner stop... I didn't saw your code. Plain objects are not iterable. You can use something like
or add custom iterator to your object.