for in 和 for of 的详细介绍以及可枚举属性

for in

它主要用于遍历对象的可枚举属性(包括数组,但不推荐用于数组)

遍历目标:对象的键(Key)

特点:它会遍历对象自身以及原型链上的所有可枚举属性

复制代码
const person = { name: 'Alice', age: 25, job: 'Engineer' };

for (let key in person) {
  console.log(key);        // 输出: "name", "age", "job"
  console.log(person[key]); // 输出: "Alice", 25, "Engineer"
}

⚠️注意:如果用 for...in 遍历数组,拿到的是数组的下标("0", "1", "2"...)

不推荐用来遍历数组哈。

for in 它会把原型链上的属性也进行遍历

刚刚我们说了:for in 它会遍历对象自身以及原型链上的所有可枚举属性

下面我们举一个例子来说明这种情况。

复制代码
const user = { name: 'Alice', age: 25 };

// 模拟某个库或同事在原型上加了属性
Object.prototype.extra = '污染属性';

for (const key in user) {
  console.log(key);
}
// 输出:
// "name"
// "age"
// "extra"   ----> 不是 user 自己的属性;是原型链上的属性

只遍对象自身的可枚举属性(1) 推荐这样遍历对象

Object.keys、Object.entries 只返回对象自身的可枚举属性,不会遍历原型链,所以更稳。

Object.keys 会返回对象自身可枚举属性键名作为数组,如: 'name', 'age'

复制代码
const user = { name: 'Alice', age: 25 };
// 模拟某个库或同事在原型上加了属性
Object.prototype.extra = '污染属性';
for (const key of Object.keys(user)) {
  console.log(key, user[key]);
}
// 输出:这样就不会输出 extra 属性了
// name  Alice
// age   25

Object.keys的简单介绍

现代浏览器全部支持,IE9+ 基本可用;兼容性最好。ES5(ES2016年)

Object.keys 会返回对象自身可枚举属性键名作为数组,不会把原型链上的属性带出来。

对数组使用 Object.keys(),返回的是数组下标:Object.keys("AA","BB") → "0", "1"

对字符串使用,返回字符索引:Object.keys("abc") → "0", "1", "2"

数字键会按数值升序排列:Object.keys({10: 'a', 2: 'b', c: 'd'}) → "2", "10", "c"

传入 null 或 undefined 会报错:TypeError

复制代码
const user = { name: 'Alice', age: 25 };
console.log(Object.keys(user)); // 输出:["name", "age"]

判断对象是否为空

复制代码
Object.keys({}).length === 0; // true

Object.entries

ES2017(ES8) 就是 2017 年发布的;推荐但要避开很老的浏览器。

只返回对象自身的可枚举属性,不会遍历原型链。

用来把对象转成键值对数组,如:\["name", "Alice", "age", 25]

对数组使用时,键是下标字符串:Object.entries('a', 'b')==> \['0', 'a', '1', 'b' ]

简单说:Object.keys()拿键,Object.values()拿值,Object.entries()同时拿键和值。

复制代码
const user = { name: 'Alice', age: 25 };
console.log(Object.entries(user));
// [ ['name', 'Alice'], ['age', 25] ]

只遍历对象自身的可枚举属性(2)

复制代码
// 模拟某个库或同事在原型上加了属性
const user = { name: 'Alice', age: 25 };
// 模拟某个库或同事在原型上加了属性
Object.prototype.extra = '污染属性';
for (const [key, value] of Object.entries(user)) {
  console.log(key, value);
}
// name Alice
// age 25

Object.keys和 for...of 的区别

1,for...in会遍历原型链上的属性,Object.keys不会遍历原型链上的属性。

2,for...in返回的是键名,Object.keys返回的是键名组成的数组。

for...of 循环

它是 ES6 (ES2015) 引入的新特性,专门用于遍历可迭代对象。

遍历目标:可迭代对象(如 Array, Map, Set, String, arguments 等)

复制代码
const colors = ['red', 'green', 'blue'];

for (let color of colors) {
  console.log(color); // 输出: "red", "green", "blue"
}

// 遍历字符串
for (let char of 'Hello') {
  console.log(char); // 输出: "H", "e", "l", "l", "o"
}

总结 for in 和 for...of

for in 主要用来遍历对象。虽然可以遍历数组,但是不推荐。

for...of 主要用来遍历数组,当然也可以是:Array, Map, Set, String, arguments

什么是可枚举属性

JavaScript 里每个属性都有一个内部标记 enumerable

enumerable: true 可枚举

enumerable: false:不可枚举

enumerable /ɪˈnjuːmərəbl/拆成四个音节来读:in-nu-mer-a-ble 因-纽-么-若-波

通过 Object.defineProperty 创建时,默认是不可枚举的

复制代码
const obj = { name: 'Alice' };
Object.defineProperty(obj, 'id', {
  value: '123',
  enumerable: false
});
// name属性是可枚举,id是不可枚举的
console.log(obj)

怎么去判断是否是可枚举属性呢 ?

通过 Object.getOwnPropertyDescriptor 来进行判断

复制代码
const obj = { name: 'Alice' };
Object.defineProperty(obj, 'id', {
  value: '123',
  enumerable: false
});
console.log(Object.getOwnPropertyDescriptor(obj, 'name').enumerable); // true
console.log(Object.getOwnPropertyDescriptor(obj, 'id').enumerable);   // false