JavaScript 对象操作:Object.keys() 与 Object.values()
在 JavaScript 开发中,对象是最常用的数据结构之一。当我们需要遍历对象属性、过滤数据或进行数据转换时,Object.keys() 和 Object.values() 是两个高频使用的方法。这两个方法专门用于获取对象的键名集合和属性值集合,配合数组方法使用,能大幅简化对象处理逻辑。
本文将系统讲解这两个方法的用法、适用场景以及实际开发中的最佳实践。
Object.keys():获取对象的所有键名
方法概述
Object.keys() 返回一个数组,包含对象自身的所有可枚举属性的键名(不含继承的属性)。语法如下:
Object.keys(obj)
其中 obj 是目标对象,返回值是一个字符串数组。
基本用法
const user = {
name: '张三',
age: 28,
city: '北京'
};
const keys = Object.keys(user);
console.log(keys); // ['name', 'age', 'city']
典型应用场景
1. 遍历对象的所有属性
const config = {
apiUrl: 'https://api.example.com',
timeout: 5000,
retries: 3
};
Object.keys(config).forEach(key => {
console.log(`${key}: ${config[key]}`);
});
输出结果:
apiUrl: https://api.example.com
timeout: 5000
retries: 3
2. 过滤对象的某些属性
const product = {
id: 1001,
name: '笔记本电脑',
price: 5999,
stock: 50,
category: '电子产品'
};
// 只获取以 'p' 开头的属性
const pKeys = Object.keys(product).filter(key => key.startsWith('p'));
console.log(pKeys); // ['price', 'product']
3. 将对象转为 Map 结构
const settings = {
theme: 'dark',
language: 'zh-CN',
notifications: true
};
const settingsMap = new Map(
Object.keys(settings).map(key => [key, settings[key]])
);
Object.values():获取对象的所有属性值
方法概述
Object.values() 返回一个数组,包含对象自身的所有可枚举属性的值。与 Object.keys() 对应,语法如下:
Object.values(obj)
基本用法
const book = {
title: 'JavaScript高级程序设计',
author: 'Nicholas C. Zakas',
pages: 724,
price: 89.00
};
const values = Object.values(book);
console.log(values);
// ['JavaScript高级程序设计', 'Nicholas C. Zakas', 724, 89]
典型应用场景
1. 快速获取所有值进行计算
const scores = {
math: 85,
english: 92,
chinese: 78,
science: 88
};
// 计算平均分
const total = Object.values(scores).reduce((sum, val) => sum + val, 0);
const average = total / Object.values(scores).length;
console.log(`总分: ${total}, 平均分: ${average.toFixed(2)}`);
// 总分: 343, 平均分: 85.75
2. 只关心值不在乎键名的场景
const weekdays = {
0: '周日',
1: '周一',
2: '周二',
3: '周三',
4: '周四',
5: '周五',
6: '周六'
};
// 获取工作日列表
const workDays = Object.values(weekdays).filter(day => !day.includes('周'));
// ['周一', '周二', '周三', '周四', '周五']
3. 提取特定类型的值
const formData = {
username: 'john_doe',
email: 'john@example.com',
age: '30',
isAdmin: 'false'
};
// 提取所有字符串类型的值
const stringValues = Object.values(formData).filter(val => typeof val === 'string');
两者配合使用
同步获取键和值
当需要同时使用键名和属性值时,可以将 Object.keys() 与 Object.values() 结合数组的索引对应关系:
const employee = {
department: '技术部',
position: '高级工程师',
salary: 25000,
joinDate: '2021-03-15'
};
const keys = Object.keys(employee);
const values = Object.values(employee);
keys.forEach((key, index) => {
console.log(`${key} -> ${values[index]}`);
});
更优雅的写法是使用 Object.entries(),本文会在后文详细说明。
深度对象处理
const nested = {
level1: {
level2a: 'value1',
level2b: 'value2'
},
level1c: 'value3'
};
// 获取第一层所有值
const firstLevelValues = Object.values(nested);
// [{ level2a: 'value1', level2b: 'value2' }, 'value3']
// 获取第二层所有键
if (typeof firstLevelValues[0] === 'object') {
const secondLevelKeys = Object.keys(firstLevelValues[0]);
// ['level2a', 'level2b']
}
常见问题与注意事项
1. 只会获取自身属性
这两个方法都只返回对象自身的属性,不包含原型链上的属性:
const parent = { a: 1 };
const child = Object.create(parent);
child.b = 2;
console.log(Object.keys(child)); // ['b'] (不会包含 a)
console.log(Object.values(child)); // [2] (不会包含 1)
2. 只获取可枚举属性
通过 Object.defineProperty 添加的不可枚举属性不会被返回:
const obj = { x: 1 };
Object.defineProperty(obj, 'y', {
value: 2,
enumerable: false
});
console.log(Object.keys(obj)); // ['x'] (y 被省略)
console.log(Object.values(obj)); // [1] (y 被省略)
3. 数组也是对象
数组是特殊的对象,索引就是键名:
const arr = ['苹果', '香蕉', '橙子'];
console.log(Object.keys(arr)); // ['0', '1', '2']
console.log(Object.values(arr)); // ['苹果', '香蕉', '橙子']
4. Symbol 属性不会被获取
默认情况下,这两个方法不会返回 Symbol 类型的键:
const symKey = Symbol('description');
const obj = {
regularKey: '值',
[symKey]: 'Symbol键的值'
};
console.log(Object.keys(obj)); // ['regularKey']
console.log(Object.values(obj)); // ['值']
如需获取 Symbol 属性,使用 Object.getOwnPropertySymbols()。
性能考量
大型对象的处理
对于包含大量属性的对象,每次调用 Object.keys() 或 Object.values() 都会遍历整个对象。如果需要多次使用,建议将结果缓存:
const largeObject = { /* 大量属性 */ };
// 不推荐:每次调用都会遍历
for (let i = 0; i < 1000; i++) {
Object.keys(largeObject).forEach(key => process(key));
}
// 推荐:缓存结果
const keys = Object.keys(largeObject);
for (let i = 0; i < 1000; i++) {
keys.forEach(key => process(key));
}
与 Object.entries() 的选择
如果同时需要键和值,使用 Object.entries() 更加高效:
const obj = { a: 1, b: 2, c: 3 };
// 低效:两次遍历
Object.keys(obj).forEach(key => {
console.log(`${key}: ${obj[key]}`);
});
// 高效:一次遍历
Object.entries(obj).forEach(([key, value]) => {
console.log(`${key}: ${value}`);
});
方法对比速查表
| 特性 | Object.keys() | Object.values() |
|---|---|---|
| 返回内容 | 键名字符串数组 | 属性值数组 |
| 返回类型 | string[] |
(string\|number\|boolean\|object)[] |
| 适用场景 | 需要操作键名时 | 需要处理属性值时 |
| 与 entries() 配合 | 需要自行映射 | 需要自行映射 |
最佳实践建议
1. 优先使用解构获取特定属性
const config = { host: 'localhost', port: 8080, secure: false };
// 推荐:直接解构需要的属性
const { host, port } = config;
2. 结合数组方法链式操作
const data = { a: 10, b: 20, c: 30, d: 40 };
// 过滤出值大于 15 的项
const filtered = Object.entries(data)
.filter(([key, value]) => value > 15)
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {});
3. 对象转数组的常见模式
const users = {
user1: { name: 'Alice' },
user2: { name: 'Bob' },
user3: { name: 'Charlie' }
};
// 获取所有用户名
const names = Object.values(users).map(user => user.name);
// ['Alice', 'Bob', 'Charlie']
掌握 Object.keys() 和 Object.values() 的用法,能让你在处理 JavaScript 对象时更加得心应手。建议在实际开发中多加练习,将这两个方法与数组方法灵活结合,可以大幅提升代码的可读性和开发效率。

暂无评论,快来抢沙发吧!