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]