for...of 语句创建的循环可以遍历对象. 在 ES6 中引入的 for...of 可以替代另外两种循环语句 for...in 和 forEach(), 而且这个新的循环语句支持新的迭代协议. for...of 允许你遍历可迭代的数据结构, 比如数组, 字符串, 映射, 集合等.
语法
- for (variable of iterable) {
- statement
- }
variable: 每个迭代的属性值被分配给 variable
iterable: 一个具有可枚举属性并且可以迭代的对象
我们使用一些示例来阐述.
Arrays
array 是简单的列表, 看上去像 object. 数组原型有多种方法, 允许在其上执行操作, 比如遍历. 下面的示例使用 for...of 来对一个 array 进行遍历操作:
- const iterable = ['mini', 'mani', 'mo'];
- for (const value of iterable) {
- console.log(value);
- }
- // Output:
- // => mini
- // => mani
- // => mo
其结果就是打印出 iterable 数组中的每一个值.
Map
Map 对象持有 key-value 对. 对象和原始值可以当作一个 key 或 value.Map 对象根据插入的方式遍历元素. 换句话说, for...of 在每次迭代中返回一个 kay-value 对的数组.
- const iterable = new Map([['one', 1], ['two', 2]]);
- for (const [key, value] of iterable) {
- console.log(`Key: ${key} and Value: ${value}`);
- }
- // Output:
- // => Key: one and Value: 1
- // => Key: two and Value: 2
- Set
Set 对象允许你存储任何类型的唯一值, 这些值可以是原始值或对象. Set 对象只是值的集合. Set 元素的迭代是基于插入顺序, 每个值只能发生一次. 如果你创建一个具有相同元素不止一次的 Set, 那么它仍然被认为是单个元素.
- const iterable = new Set([1, 1, 2, 2, 1]);
- for (const value of iterable) {
- console.log(value);
- }
- // Output:
- // => 1
- // => 2
尽管我们创建的 Set 有多个 1 和 2, 但遍历输出的只有 1 和 2.
String
字符串用于以文本形式存储数据.
- const iterable = 'javascript';
- for (const value of iterable) {
- console.log(value);
- }
- // Output:
- // => "j"
- // => "a"
- // => "v"
- // => "a"
- // => "s"
- // => "c"
- // => "r"
- // => "i"
- // => "p"
- // => "t"
在这里, 对字符串执行迭代, 并打印出每个索引上 (index) 的字符.
Arguments Object
把一个参数对象看作是一个类似数组的对象, 与传递给函数的参数相对应. 这是一个用例:
- function args() {
- for (const arg of arguments) {
- console.log(arg);
- }
- }
- args('a', 'b', 'c');
- // Output:
- // => a
- // => b
- // => c
你可能在想, 到底发生了什么? 正如我前面说过的, 当调用函数时, 参数会接收传入 args()函数的任何参数. 因此, 如果我们将 20 个参数传递给 args()函数, 我们将输出 20 个参数.
在上面的示例基础上做一些调整, 比如给 args()函数, 传入一个对象, 数组和函数:
- function fn(){
- return 'functions';
- }
- args('a', 'w3cplus', 'c',{
- 'name': 'airen'
- },['a',1,3],fn());
- // Output:
- // => "a"
- // => "w3cplus"
- // => "c"
- // => Object {
- // => "name": "airen"
- // =>
- }
- // => Array [
- // => "a",
- // => 1,
- // => 3
- // => ]
- // => "functions"
- Generators
生成器是一个函数, 它可以退出函数, 稍后重新进入函数.
- function* generator(){
- yield 1;
- yield 2;
- yield 3;
- };
- for (const g of generator()) {
- console.log(g);
- }
- // Output:
- // => 1
- // => 2
- // => 3
function* 定义一个生成器函数, 该函数返回生成器对象. 更多关于生成器相关的信息, 可以点击这里.
关闭迭代器
JavaScript 中提供了四种已知的终止循环的方法: break,continue,return 和 throw. 来看一个示例:
- const iterable = ['mini', 'mani', 'mo'];
- for (const value of iterable) {
- console.log(value);
- break;
- }
- // Output:
- // => mini
在这个例子中, 我们使用 break 关键词来终止一个循环, 并且只打印出一个 mini.
普通对象不可迭代
for...of 循环只能和迭代一起工作. 但普通对象是不可迭代的. 让我们看看:
- const obj = { fname: 'foo', lname: 'bar' };
- for (const value of obj) { // TypeError: obj[Symbol.iterator] is not a function
- console.log(value);
- }
在这里, 我们定义了一个普通对象 obj, 当我们尝试 for...of 给 obj 进行操作时, 会报错: TypeError: obj[Symbol.iterator] is not a function.
我们可以把一个类似数组的对象转找成一个数组. 对象将具有 length 属性, 它的元素可以被索引. 来看一个示例:
- const obj = { length: 3, 0: 'foo', 1: 'bar', 2: 'baz' };
- const array = Array.from(obj);
- for (const value of array) {
- console.log(value);
- }
- // Output:
- // => foo
- // => bar
- // => baz
Array.from()方法从类似数组 (Array-lik) 或迭代对象中创建了一个新的数组实例.
for...of vs. for...in
for...in 在循环中将遍历对象中所有可枚举属性.
- Array.prototype.newArr = () => {};
- Array.prototype.anotherNewArr = () => {};
- const array = ['foo', 'bar', 'baz'];
- for (const value in array) {
- console.log(value);
- }
- // Outcome:
- // => 0
- // => 1
- // => 2
- // => newArr
- // => anotherNewArr
for...in 不仅可以枚举数组里声明的值, 它还可以从构造函数的原型中寻找继承的非枚举属性, 比如上例中的 newArr 和 anotherNewArr, 并将它们打印出来.
for...of 可以对数组和对象等做更具体的操作, 但并不表示包括所有对象.
注意: 任何具有 Symbol.iterator 属性的元素都是可迭代的.
- Array.prototype.newArr = function() {};
- const array = ['foo', 'bar', 'baz'];
- for (const value of array) {
- console.log(value);
- }
- // Outcome:
- // => foo
- // => bar
- // => baz
for...of 不考虑构造函数原型的不可枚举属性. 它只需要查找可枚举属性并将其打印出来.
总结
理解 for...of 循环在开发过程中的用法, 可以节省很多时间. 希望本文能帮助您理解和编写 JavaScript 开发中的更好的循环结构. 从而让你编码更快乐!
- Learning ES6: for-of loop
- The JavaScript Looping Evolution
- Iterables and iterators in ECMAScript 6 https://2ality.com/2015/02/es6-iteration.html
来源: http://www.css88.com/web/javascript/12698.html