# 17. The `for-of` loop
## 17.1 Overview
`for-of` is a new loop in ES6 that replaces both `for-in` and `forEach()` and supports the new iteration protocol.
Use it to loop over *iterable* objects (Arrays, strings, Maps, Sets, etc.; see Chap. “[Iterables and iterators](ch_iteration.html#ch_iteration)”):
```const` `iterable` `=` `[``'a'``,` `'b'``];`
`for` `(``const` `x` `of` `iterable``)` `{`
`console``.``log``(``x``);`
`}`
`// Output:`
`// a`
`// b`
`break` and `continue` work inside `for-of` loops:
```for` `(``const` `x` `of` `[``'a'``,` `''``,` `'b'``])` `{`
`if` `(``x``.``length` `===` `0``)` `break``;`
`console``.``log``(``x``);`
`}`
`// Output:`
`// a`
Access both elements and their indices while looping over an Array (the square brackets before `of` mean that we are using [destructuring](ch_destructuring.html#ch_destructuring)):
```const` `arr` `=` `[``'a'``,` `'b'``];`
`for` `(``const` `[``index``,` `element``]` `of` `arr``.``entries``())` `{`
`console``.``log``(`````${``index``}``. ``${``element``}`````);`
`}`
`// Output:`
`// 0. a`
`// 1. b`
Looping over the \[key, value\] entries in a Map (the square brackets before `of` mean that we are using [destructuring](ch_destructuring.html#ch_destructuring)):
```const` `map` `=` `new` `Map``([`
`[``false``,` `'no'``],`
`[``true``,` `'yes'``],`
`]);`
`for` `(``const` `[``key``,` `value``]` `of` `map``)` `{`
`console``.``log``(`````${``key``}`` => ``${``value``}`````);`
`}`
`// Output:`
`// false => no`
`// true => yes`
## 17.2 Introducing the `for-of` loop
`for-of` lets you loop over data structures that are *iterable*: Arrays, strings, Maps, Sets and others. How exactly iterability works is explained in Chap. “[Iterables and iterators](ch_iteration.html#ch_iteration)”. But you don’t have to know the details if you use the `for-of` loop:
```const` `iterable` `=` `[``'a'``,` `'b'``];`
`for` `(``const` `x` `of` `iterable``)` `{`
`console``.``log``(``x``);`
`}`
`// Output:`
`// a`
`// b`
`for-of` goes through the items of `iterable` and assigns them, one at a time, to the loop variable `x`, before it executes the body. The scope of `x` is the loop, it only exists inside it.
You can use `break` and `continue`:
```for` `(``const` `x` `of` `[``'a'``,` `''``,` `'b'``])` `{`
`if` `(``x``.``length` `===` `0``)` `break``;`
`console``.``log``(``x``);`
`}`
`// Output:`
`// a`
`for-of` combines the advantages of:
- Normal `for` loops: `break`/`continue`; usable in generators
- `forEach()` methods: concise syntax
## 17.3 Pitfall: `for-of` only works with iterable values
The operand of the `of` clause must be iterable. That means that you need a helper function if you want to iterate over plain objects (see “[Plain objects are not iterable](ch_iteration.html#sec_plain-objects-not-iterable)”). If a value is Array-like, you can convert it to an Array via [`Array.from()`](ch_arrays.html#Array_from):
```// Array-like, but not iterable!`
`const` `arrayLike` `=` `{` `length``:` `2``,` `0``:` `'a'``,` `1``:` `'b'` `};`
`for` `(``const` `x` `of` `arrayLike``)` `{` `// TypeError`
`console``.``log``(``x``);`
`}`
`for` `(``const` `x` `of` `Array``.``from``(``arrayLike``))` `{` `// OK`
`console``.``log``(``x``);`
`}`
## 17.4 Iteration variables: `const` declarations versus `var` declarations
If you `const`-declare the iteration variable, a fresh *binding* (storage space) will be created for each iteration. That can be seen in the following code snippet where we save the current binding of `elem` for later, via an arrow function. Afterwards, you can see that the arrow functions don’t share the same binding for `elem`, they each have a different one.
```const` `arr` `=` `[];`
`for` `(``const` `elem` `of` `[``0``,` `1``,` `2``])` `{`
`arr``.``push``(()` `=>` `elem``);` `// save `elem` for later`
`}`
`console``.``log``(``arr``.``map``(``f` `=>` `f``()));` `// [0, 1, 2]`
`// `elem` only exists inside the loop:`
`console``.``log``(``elem``);` `// ReferenceError: elem is not defined`
A `let` declaration works the same way as a `const` declaration (but the bindings are mutable).
It is instructive to see how things are different if you `var`-declare the iteration variable. Now all arrow functions refer to the same binding of `elem`.
```const` `arr` `=` `[];`
`for` `(``var` `elem` `of` `[``0``,` `1``,` `2``])` `{`
`arr``.``push``(()` `=>` `elem``);`
`}`
`console``.``log``(``arr``.``map``(``f` `=>` `f``()));` `// [2, 2, 2]`
`// `elem` exists in the surrounding function:`
`console``.``log``(``elem``);` `// 2`
Having one binding per iteration is very helpful whenever you create functions via a loop (e.g. to add event listeners).
You also get per-iteration bindings in `for` loops (via `let`) and `for-in` loops (via `const` or `let`). Details are explained in [the chapter on variables](ch_variables.html#sec_let-const-loop-heads).
## 17.5 Iterating with existing variables, object properties and Array elements
So far, we have only seen `for-of` with a declared iteration variable. But there are several other forms.
You can iterate with an existing variable:
```let` `x``;`
`for` `(``x` `of` `[``'a'``,` `'b'``])` `{`
`console``.``log``(``x``);`
`}`
You can also iterate with an object property:
```const` `obj` `=` `{};`
`for` `(``obj``.``prop` `of` `[``'a'``,` `'b'``])` `{`
`console``.``log``(``obj``.``prop``);`
`}`
And you can iterate with an Array element:
```const` `arr` `=` `[];`
`for` `(``arr``[``0``]` `of` `[``'a'``,` `'b'``])` `{`
`console``.``log``(``arr``[``0``]);`
`}`
## 17.6 Iterating with a destructuring pattern
Combining `for-of` with destructuring is especially useful for iterables over \[key, value\] pairs (encoded as Arrays). That’s what Maps are:
```const` `map` `=` `new` `Map``().``set``(``false``,` `'no'``).``set``(``true``,` `'yes'``);`
`for` `(``const` `[``k``,``v``]` `of` `map``)` `{`
`console``.``log``(```key = ``${``k``}``, value = ``${``v``}`````);`
`}`
`// Output:`
`// key = false, value = no`
`// key = true, value = yes`
`Array.prototype.entries()` also returns an iterable over \[key, value\] pairs:
```const` `arr` `=` `[``'a'``,` `'b'``,` `'c'``];`
`for` `(``const` `[``k``,``v``]` `of` `arr``.``entries``())` `{`
`console``.``log``(```key = ``${``k``}``, value = ``${``v``}`````);`
`}`
`// Output:`
`// key = 0, value = a`
`// key = 1, value = b`
`// key = 2, value = c`
Therefore, `entries()` gives you a way to treat iterated items differently, depending on their position:
```/** Same as arr.join(', ') */`
`function` `toString``(``arr``)` `{`
`let` `result` `=` `''``;`
`for` `(``const` `[``i``,``elem``]` `of` `arr``.``entries``())` `{`
`if` `(``i` `>` `0``)` `{`
`result` `+=` `', '``;`
`}`
`result` `+=` `String``(``elem``);`
`}`
`return` `result``;`
`}`
This function is used as follows:
```
``> toString(['eeny', 'meeny', 'miny', 'moe'])
'eeny, meeny, miny, moe'
```
Next: [18. New Array features](ch_arrays.html)
- 关于本书
- 目录简介
- 关于这本书你需要知道的
- 序
- 前言
- I 背景
- 1. About ECMAScript 6 (ES6)
- 2. 常见问题:ECMAScript 6
- 3. 一个JavaScript:在 ECMAScript 6 中避免版本化
- 4. 核心ES6特性
- II 数据
- 5. New number and Math features
- 6. 新的字符串特性
- 7. Symbol
- 8. Template literals
- 第9章 变量与作用域
- 第10章 解构
- 第11章 参数处理
- III 模块化
- 12. ECMAScript 6中的可调用实体
- 13. 箭头函数
- 14. 除了类之外的新OOP特性
- 15. 类
- 16. 模块
- IV 集合
- 17. The for-of loop
- 18. New Array features
- 19. Maps and Sets
- 20. 类型化数组
- 21. 可迭代对象和迭代器
- 22. 生成器( Generator )
- V 标准库
- 23. 新的正则表达式特性
- 24. 异步编程 (基础知识)
- 25. 异步编程的Promise
- VI 杂项
- 26. Unicode in ES6
- 27. 尾部调用优化
- 28 用 Proxy 实现元编程
- 29. Coding style tips for ECMAScript 6
- 30. 概述ES6中的新内容
- 注释
- ES5过时了吗?
- ==个人笔记==