ES6定义了一个新循环语句:for/of。这种新循环虽然使用for关键字,但它与常规for循环是完全不同的两种循环(for/of与for/in循环也是完全不同的)。for/of 循环专门用于可迭代对象。第12章会解释到底什么对象是可迭代对象,但现在只要知道数组、字符串、集合和映射都是可迭代的就行了。它们都是一组或一批元素,可以使用 for/of 循环来循环或迭代这些元素。例如,下面这个例子演示了如何迭代一个数值数组并计算所有数值之和:
let data=[1,2,3,4,5,6,7,8,9],sum=0; for(let element of data){ sum+=element; } console.log(sum);
表面上看,这个语法跟常规for循环很像,都是for关键字后跟着一对圆括号,其中包含如何循环的细节。具体来说,这里的圆括号中包含一个变量声明(对于已经声明的变量,只包含变量名即可),然后是of关键字和一个求值为可迭代对象的表达式(比如这里的data数组)。与所有循环一样,for/of循环的循环体紧跟在圆括号之后,通常包含在花括号中。在上面的代码中,循环体对应data数组中的每个元素都会运行一次。在每次执行循环体之前,都会把数组的下一个元素赋值给元素变量。数组元素是按照从头到尾的顺序迭代的。数组迭代是“实时”的,即迭代过程中的变化可能影响迭代的输出。如果修改前面的代码,在循环内添加一行 data.push(sum),则会创建一个无穷循环。因为迭代永远不会触及数组的最后一个元素。
for/of与对象
对象(默认)是不可迭代的。运行时尝试对常规对象使用for/of会抛出TypeError:
let o={x:1, y:2, z:3}; //抛出TypeError,因为o不是可迭代对象 //Uncaught TypeError: o is not iterable for(let element of o){ console.log(element); }
如果想迭代对象的属性,可以使用for/in循环,或者基于Object.keys()方法的结果使用for/of:
let o={x:1, y:2, z:3}; let keys=""; for(let k of Object.keys(o)){ keys+=k; } console.log(keys);
这是因为Object.keys()返回一个对象属性名的数组,而数组是可以通过for/of来迭代的。也要注意,这种对象的键的迭代并不像上面例子那样是实时的,在循环体内修改对象o不会影响迭代。如果你不在乎对象的键,也可以像下面这样迭代每个键对应的值:
let sum=0; for(let v of Object.values(o)){ sum+=v; } console.log(sum);
如果你既想要对象属性的键,也想要属性的值,可以基于Object.entries()和解构赋值来使用for/of:
let o={x:1, y:2, z:3}; let pairs=""; for(let [k,v] of Object.entries(o)){ pairs+=k+v; } console.log(pairs);
Object.entries()返回一个数组的数组,其中每个内部数组表示对象的一个属性的键/值对。这里使用解构赋值把这些内部数组拆开,并将它们的元素赋值给两个变量。
for/of与字符串
字符串在ES6中是可以逐个字符迭代的:
let frequency={}; for(let letter of "wangzhanchengxu"){ if(frequency[letter]){ frequency[letter]++; }else{ frequency[letter]=1; } } console.log(frequency);