for in
要很好的掌握for-in
的使用你可能只需要记住下面一句话:
以特定顺序遍历一个对象及其原型链的所有可枚举属性(但是不包括 Symbol)。
我们先上代码,再一一解释。
const sym = Symbol("key");// 创建一个对象const obj = { key: 23, name: "singcl", action: Symbol("action"), [sym]: "symbol", 3: "the number is 3", 1: "the number is 1"};// 使用 Object.defineProperty() 给obj添加一个不可枚举属性Object.defineProperty(obj, "water", { enumerable: false, value: "这是一个不可枚举属性"});// 使用 Object.defineProperty() 给obj添加一个可枚举属性Object.defineProperty(obj, "people", { enumerable: true, value: "这是一个可枚举属性"});// 设置对象原型Object.setPrototypeOf(obj, { protoKey: "这是一个定义在原型上的属性" });// for-in 遍历对象const res = [];for (const key in obj) { res.push(key);}// 输出遍历结果console.log(res); // [ '1', '3', 'key', 'name', 'action', 'people', 'protoKey' ]console.log(obj.protoKey); // 这是一个定义在原型上的属性console.log(obj.water); // 这是一个不可枚举属性console.log(obj.people); // 这是一个可枚举属性console.log(obj.propertyIsEnumerable("water")); // falseconsole.log(obj.propertyIsEnumerable("people")); // trueconsole.log(obj.propertyIsEnumerable(sym)); // true复制代码
现在我们就来一样解释:
1.特定顺序
我们在obj
上添加的属性的顺序和我们最终for-in
循环输出的结果的顺序并不一致,那么for-in
遍历到底是按什么顺序遍历的呢?
其实是按以下顺序遍历的:
- 首先遍历所有数值键,按照数值升序排列。
- 其次遍历所有字符串键,按照加入时间升序排列。
最后遍历所有 Symbol 键,按照加入时间升序排列
对照上面的代码看看是不是呢。
2.对象及其原型链
for-in
循环遍历对象时候会遍历对象以及对象原型链上的属性。上面protoKey
是定义在对象的原型上而不是对象本身上。但是依然被for-in
遍历到了。
3.可枚举属性
water
是我们使用Object.defineProperty()
定义在 obj 上的一个不可枚举属性people
是我们使用Object.defineProperty()
定义在 obj 上的一个可枚举属性
观察for-in
循环的输出结果我们看的people
被遍历到了,而water
却没有被遍历到。我们再次来确认下:
// 查看obj 上是否有water和people属性console.log(obj.water); // 这是一个不可枚举属性console.log(obj.people); // 这是一个可枚举属性// 确定water 和 people 是否可枚举console.log(obj.propertyIsEnumerable("water")); // falseconsole.log(obj.propertyIsEnumerable("people")); // true复制代码
的确 people
是 obj 上可枚举属性,被遍历到了,而water
是 obj 上不可枚举属性,没有被遍历到。
obj 上key, name, action
等通过字面量方式添加的属性默认是可枚举的。
4.但是不包括 Symbol
你可能有疑问: obj 上 Symbol
类型的属性sym
也没有被遍历到,是不是因为它是不可枚举属性? 那么我们验证下:
console.log(obj.propertyIsEnumerable(sym)); // true复制代码
咦?obj 上 Symbol
类型的属性sym
是可枚举的,但是却没有被遍历到。
这就是为什么要单独指出:可枚举属性(但是不包含 Symbol) 要想获得Symbol
类型的属性,我们可以使用Object.getOwnPropertySymbols()
。这里就不讲了,如果有兴趣可以自己去了解。
总结
以特定顺序遍历一个对象及其原型链的所有可枚举属性(但是不包括 Symbol)。
for-in
循环的4个要点:
- 特定顺序
- 对象及其原型链
- 可枚举属性
- 不包含 Symbol 类型
参考: