Object.keys、values、entries 和 fromEntries 有什么区别?
简化版
Object.keys 返回对象自身可枚举字符串键,Object.values 返回对应值,Object.entries 返回键值对数组;Object.fromEntries 反过来把键值对列表转成对象。
它们都只处理对象自身的可枚举字符串属性,不包含继承属性和 Symbol 属性。常见用途是对象遍历、对象过滤、对象映射,以及和 Map 之间互相转换。
详细版
const user = { id: 1, name: "Ada" };
Object.keys(user); // ["id", "name"]
Object.values(user); // [1, "Ada"]
Object.entries(user); // [["id", 1], ["name", "Ada"]]
fromEntries 可以把键值对还原成对象:
const pairs = [["id", 1], ["name", "Ada"]];
const user = Object.fromEntries(pairs);
过滤对象字段时很常用:
const clean = Object.fromEntries(
Object.entries(user).filter(([key]) => key !== "password")
);
需要注意,它们不会拿到不可枚举属性、继承属性和 Symbol 键。若要拿全部自有键,通常看 Reflect.ownKeys。
完整版教学
一、这组 API 解决什么问题
ES2017 以后,对象遍历不再只能先拿 key 再手动索引取值。keys、values、entries 分别服务三种视角。
object -> keys -> key list
object -> values -> value list
object -> entries -> pair list
pairs -> fromEntries -> object
这组 API 的核心是把对象转换成数组管道,处理完再转回对象。
二、keys、values、entries 的返回值
const obj = { a: 1, b: 2 };
console.log(Object.keys(obj));
console.log(Object.values(obj));
console.log(Object.entries(obj));
| API | 返回结构 | 适合场景 |
|---|---|---|
Object.keys | ["a", "b"] | 只关心字段名 |
Object.values | [1, 2] | 聚合值 |
Object.entries | [["a", 1], ["b", 2]] | 同时处理键和值 |
比如统计总分,用 values 足够;字段重命名或过滤,用 entries 更舒服。
三、它们只看自身可枚举字符串属性
const symbolKey = Symbol("id");
const obj = Object.create({ inherited: 1 });
Object.defineProperty(obj, "hidden", {
value: 2,
enumerable: false
});
obj.name = "Ada";
obj[symbolKey] = 3;
console.log(Object.keys(obj)); // ["name"]
继承属性、不可枚举属性、Symbol 属性都不会出现。
四、fromEntries 适合对象管道转换
Object.fromEntries 接收可迭代的键值对,不只数组,Map 也可以。
const map = new Map([
["theme", "dark"],
["pageSize", 20]
]);
const config = Object.fromEntries(map);
对象过滤:
function pick(obj, allowList) {
return Object.fromEntries(
Object.entries(obj).filter(([key]) => allowList.includes(key))
);
}
五、顺序和覆盖规则
对象属性顺序遵循整数索引键、字符串键、Symbol 键的规则;这组 API 只返回字符串键,因此数字样式键会按数字升序提前。
const obj = { b: 1, 2: "two", a: 3, 1: "one" };
console.log(Object.keys(obj)); // ["1", "2", "b", "a"]
fromEntries 遇到重复 key,后面的会覆盖前面的。
Object.fromEntries([["a", 1], ["a", 2]]); // { a: 2 }
六、和 Map 的转换关系
Map 天然就是键值对迭代结构。
const obj = { a: 1 };
const map = new Map(Object.entries(obj));
const back = Object.fromEntries(map);
如果 key 是对象,转成普通对象会被字符串化,不应这样用。
const key = {};
Object.fromEntries([[key, 1]]);
// { "[object Object]": 1 }
七、常见误区与追问
- 误区:Object.entries 会返回所有属性。 它只返回自身可枚举字符串属性。
- 误区:Object.values 的顺序完全等于写入顺序。 整数索引键会先按数字升序排列。
- 误区:fromEntries 能无损转换任意 Map。 对象键会被转成属性键,可能变成字符串。
- 误区:Symbol 键会出现在 keys 里。 Symbol 键需要
Object.getOwnPropertySymbols或Reflect.ownKeys。 - 追问:如何实现对象字段过滤? 可以
entries -> filter -> fromEntries。 - 追问:重复 key 怎么处理? 后出现的键值对覆盖前面的值。
八、加强记忆
记住一个闭环:
Object.entries(obj)
-> array methods
-> Object.fromEntries(pairs)
面试回答时先说返回值,再说覆盖范围,最后讲对象过滤、对象映射、Map 转换三个应用。这样能把 API 和真实开发串起来。