They both iterate but over lists but behave slightly differently.
for...in iterates over the keys of the list - think keys in an object or indices in an array. Think of it like looping over what’s returned for Object.keys
for...of iterates over the values of the list - think values stored in the array or values in the object. Think of it like looping over what’s returned with Object.values
Example with String
const a = 'hello world';
for (let i in a) {
console.log(i);
}
// 0
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9
// 10
for (let i of a) {
console.log(i);
}
// h
// e
// l
// l
// o
// w
// o
// r
// l
// d
Example with Set
You can run for...in on a data set with no keys. As long as it is iterable, if the data set does not have any keys, it will return undefined.
a = new Set([1, 2, 3]);
for (let key in a) {
console.log(key);
}
// undefined
for (let values of a) {
console.log(values);
}
// 1
// 2
// 3
Example with Map
With a map, all the values are stored as entries similar to each entry you might get with Object.entries
const a = new Map();
a.set('a', 1);
a.set('b', 2);
a.set('c', 3);
for (let key in a) {
console.log(key);
}
// undefined
for (let values of a) {
console.log(values);
}
['a', 1][('b', 2)][('c', 3)];
ES5
In ES5, it was illegal to run for...of on anything but an array. This has since been changed to allow running for...of on any value that implements Symbol.iterator.
Symbol Iterator
Some native values come with a built in implementation of the @@iterator method. You can also build your own iterable value by manually implementing your own iterable using generators.
var myIterable = {};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
for (let val of myIterable) {
console.log(val);
}
// 1
// 2
// 3
When a variable is iterable, it allows you to spread it using the spread operator
[...myIterable];
// [1, 2, 3]