for of、for in

for in

for...in 循环实际是为循环可枚举(enumerable)对象而设计的:

如果表示要迭代的对象的变量值为 nullundefinedfor...in 语句在 ES5 中不会抛出错误,只是不执行循环体,建议使用 for...in 之前,先检测确认该对象的值不是 nullundefined

1
2
3
4
5
let arr = null;
for (let prop in arr) {
console.log(prop);
}
// 不会打印出任何东西

循环一个 {}

1
2
3
4
5
6
7
8
let obj = { a: 1, b: 2, c: 3 };
for(let prop in obj) {
console.log(prop + ": " + obj[prop]);
}
// 输出
// a: 1
// b: 2
// c: 3

可以用来循环一个数组,但不推荐,因为不像对象,数组的 index 跟普通的对象属性不一样,是重要的数值序列指标。

1
2
3
4
5
6
7
8
9
10
let arr = ["a","b","c","d","e"];
for(let prop in arr) {
console.log(prop + ": " + arr[prop])
}
// 输出
// 0: a
// 1: b
// 2: c
// 3: d
// 4: e

总之,for...in 是用来循环带有字符串 key 的对象的方法。

for of

ES6 在 for 和 for…in 基础上,新增了一个 for of 循环,在迭代器产生的一系列值上循环。

for...of 循环的值必须是一个 iterable ,或者说它必须是可以转换 / 封箱到一个 iterable 对象的值。iterable 就是一个能够产生迭代器供循环使用的对象。

JavaScript 中默认为(或提供)iterable 的标准内建值包括:

  • Arrays
  • Strings
  • Generators
  • Collections / TypedArrays

默认情况下平凡的对象并不适用 for…of 循环,因为他们并没有默认的迭代器。

循环一个数组(Array):

1
2
3
4
5
6
7
8
9
10
let arr = ["a","b","c","d","e"];
for (let value of arr) {
console.log(value);
}
// 输出
// a
// b
// c
// d
// e

我们可以使用 const 来替代 let,这样它就变成了在循环里的不可修改的静态变量。

1
2
3
4
5
6
7
8
9
10
let arr = ["a","b","c","d","e"];
for (const value of arr) {
console.log(value);
}
// 输出
// a
// b
// c
// d
// e

循环一个字符串:

原生字符串值 “gzl” 被强制类型转换 / 封箱到等价的 String 封装对象中,而 Strings 默认是一个 iterable。

1
2
3
4
5
6
7
8
let str = "gzl";
for (let value of str) {
console.log(value);
}
// 输出
// g
// z
// l

参考

你不知道的JavaScript(下卷)P110