JS 对象转数组的常用方法:Object.values 与 entries 详解
深入详解 JavaScript 中使用 Object.values 与 Object.entries 将对象转换为数组的实用方法,包含语法解析、执行原理、属性排序机制、常见业务场景与选型对比。
map、filter、reduce 等数组高阶方法。将对象转换为数组是处理复杂业务逻辑、列表组件渲染以及多维数据统计的通用前提。ES2017(ES8)正式引入了 Object.values() 与 Object.entries(),它们与传统的 Object.keys() 构成了原生标准的对象转数组工具链:Object.values 提取对象的属性值组成一维数组,Object.entries 提取键值对元组组成二维数组。本文将从语法规范、底层遍历规则、高频应用模式到反向重构闭环,系统解析这两个方法的技术细节与工程实践。
一、为什么需要将对象转为数组:转换全景与形态分类
JavaScript 的对象与数组具有不同的设计定位。对象是具名属性的离散映射容器,不具备类似 Array.prototype 提供的顺序流式处理管道。当我们需要对对象数据执行如下操作时,将其转换为数组通常是最高效的解决途径:
- 使用高阶函数链式变换:使用
.filter()剔除空属性、使用.reduce()累计计算总和、使用.map()转换字段形态。 - 对接 UI 渲染框架:React、Vue 等组件视图通常需要针对列表数组进行渲染(如
v-for或array.map(...))。 - 序列化与传输适配:构造 URL 查询参数字符串(Query String)或向只接受二维数组格式的数据结构(如
Map构造函数)注入数据。
在原生 JavaScript 中,根据所需的数据维度不同,通常有三种转换形态:只取键名、只取属性值、同时保留键名与属性值。下图清晰展示了这三种转换方式的数据流向与结构差异:
二、Object.values 详解:纯值列表提取与数据聚合
Object.values() 方法返回一个给定对象自身的所有可枚举属性值的数组。其输出形态为一个一维数组,数组中元素的排列顺序与使用 for...in 循环遍历该对象时返回的顺序一致(排除了原型链属性)。
2.1 基本语法与基础用法
语法定义十分简洁:
Object.values(obj)
参数 obj 表示目标对象。若传入基本类型(如数字、字符串),运行时会将其自动装箱为对应的包装对象;若传入 null 或 undefined,则会抛出 TypeError。
// 示例:基础商品价格配置
const productPrices = {
apple: 8.5,
banana: 4.2,
orange: 6.0
};
const prices = Object.values(productPrices);
console.log(prices);
// 示例输出: [ 8.5, 4.2, 6 ]
2.2 典型场景:数值聚合与统计计算
当业务数据以字典形式存储(如统计报表、各科成绩、各渠道销售额),但下游只关心总值或均值时,Object.values 是最优解。通过配合 Array.prototype.reduce,能够以纯函数的形式在一行内完成聚合,无需手动维护外部累加变量:
// 示例:各科目考试成绩汇总
const scores = {
math: 92,
english: 88,
chemistry: 95,
physics: 79
};
// 1. 计算总分
const totalScore = Object.values(scores).reduce((sum, val) => sum + val, 0);
// 2. 计算平均分
const avgScore = totalScore / Object.values(scores).length;
// 3. 校验是否存在不及格单科(低于60分)
const hasFailedSubject = Object.values(scores).some(val => val < 60);
console.log("总分:", totalScore); // 示例输出: 总分: 354
console.log("平均分:", avgScore); // 示例输出: 平均分: 88.5
console.log("有无不及格:", hasFailedSubject); // 示例输出: 有无不及格: false
Object.values() 返回的新数组本身是一个独立的 Array 实例,对该数组调用 push 或 sort 不会影响原对象。但若原对象的属性值是引用类型(如子对象或嵌套数组),新数组中保存的仍然是该对象的内存引用。修改引用对象的内部属性会同步反映在原对象上。
三、Object.entries 详解:二维键值对与结构变换
Object.entries() 方法返回一个给定对象自身可枚举属性的键值对数组。其结构为二维数组,内部每一个元素均为一个包含两个项的元组 [key, value],其中 key 始终为字符串(即使原对象的键是数字,也会转为字符串),value 为对应的属性值。
3.1 解构遍历与现代迭代
二维元组结构与 ES6 的数组解构语法(Array Destructuring)天然契合。在循环或高阶函数中,可以直接解构出 [key, value],逻辑表达直观:
const inventory = {
pens: 120,
notebooks: 45,
erasers: 0
};
// 使用 for...of 结合数组解构遍历
for (const [item, count] of Object.entries(inventory)) {
console.log(`${item} 当前库存: ${count}`);
}
// 示例输出:
// pens 当前库存: 120
// notebooks 当前库存: 45
// erasers 当前库存: 0
3.2 典型场景:复杂属性过滤与 URL 查询参数组装
在实际项目中,纯粹的键名或纯粹的值往往无法满足筛选需求。例如,在提交 HTTP GET 请求前,需要将查询参数对象中值为 null、undefined 或空字符串的非法字段剔除,并完成 URL 编码:
const queryParams = {
keyword: "javascript",
page: 1,
pageSize: 20,
filterTag: null, // 空字段
sort: "createTime_desc"
};
// 1. 过滤掉 null 与 undefined 字段
const validEntries = Object.entries(queryParams).filter(
([key, value]) => value !== null && value !== undefined
);
// 2. 构造 URL 查询参数字符串
const queryString = validEntries
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.join("&");
console.log(queryString);
// 示例输出: keyword=javascript&page=1&pageSize=20&sort=createTime_desc
// 3. 亦可直接传入原生 URLSearchParams 构造器
const searchParams = new URLSearchParams(validEntries);
console.log(searchParams.toString());
// 示例输出: keyword=javascript&page=1&pageSize=20&sort=createTime_desc
3.3 双向闭环:通过 Object.fromEntries 实现清洗与重构
在 ES2019 中,JavaScript 补充了 Object.fromEntries() 方法。它正是 Object.entries() 的逆操作,能够将二维键值对数组无缝还原为一个普通对象。
这形成了一个强大的对象数据变换工程范式:对象输入 → Object.entries 转换为二维数组 → 数组高级方法处理(filter/map)→ Object.fromEntries 重新组装为纯净对象。
const rawForm = {
username: " alice_dev ",
email: "ALICE@EXAMPLE.COM",
age: 26,
internalToken: "secret_12345", // 需要剔除的私有属性
tempNote: ""
};
// 闭环处理:剔除内部私有属性并清洗字符串空格
const cleanedObject = Object.fromEntries(
Object.entries(rawForm)
.filter(([key]) => !key.startsWith("internal") && !key.startsWith("temp"))
.map(([key, value]) => [
key,
typeof value === "string" ? value.trim().toLowerCase() : value
])
);
console.log(cleanedObject);
// 示例输出:
// {
// username: "alice_dev",
// email: "alice@example.com",
// age: 26
// }
四、关键规则与边界条件解析
虽然 Object.values 与 Object.entries 易于上手,但在处理包含特殊键名、继承关系或非对象入参时,必须明确其底层规范边界,以避免难以察觉的隐性错误。
4.1 属性遍历顺序规范(ES2015 内部算法)
ECMAScript 规范明确规定了自身属性键的遍历次序(基于 [[OwnPropertyKeys]] 算法)。Object.values 与 Object.entries 严格遵循该次序:
- 整数索引键:所有可以转化为 32 位非负整数的属性名,按照升序数值顺序排列。
- 普通字符串键:其余非整数键名,按照添加到对象的实际插入时间顺序排列。
- Symbol 键:
Object.values与Object.entries会完全忽略所有 Symbol 属性。如果需要获取 Symbol 属性对应的内容,必须使用Object.getOwnPropertySymbols()。
const symKey = Symbol("customId");
const mixedObj = {
"b": "second string",
"10": "ten",
"a": "first string",
"2": "two",
[symKey]: "symbol value" // 会被忽略
};
console.log(Object.values(mixedObj));
// 示例输出: [ "two", "ten", "second string", "first string" ]
// 说明: 整数键 "2"、"10" 优先按数值升序输出,随后是插入顺序的 "b"、"a",Symbol 被排除
4.2 原型链继承属性与不可枚举属性
与 for...in 循环不同,Object.values 与 Object.entries 不会遍历原型链上的任何继承属性,省去了调用 hasOwnProperty() 进行过滤的手续。同时,通过 Object.defineProperty 设置为 enumerable: false 的属性也会被直接忽略。
4.3 基础数据类型传参时的自动装箱
若向 Object.values 或 Object.entries 传入非对象参数:
- 字符串:会被装箱为 String 对象,字符串的字符索引(0, 1, ...)成为键名,字符本身成为值。例如
Object.entries("foo")返回[["0", "f"], ["1", "o"], ["2", "o"]]。 - 数字或布尔值:包装后没有自身可枚举属性,返回空数组
[]。 - null 或 undefined:无法被装箱为对象,直接抛出
TypeError: Cannot convert undefined or null to object。在动态入参场景中,应做好空值保护(如Object.values(data || {}))。
五、常用转换方法选型与工程总结
在实际项目编码中,面对不同的数据结构与业务目的,应遵循清晰的选型标准。下表与图示总结了 Object.keys、Object.values、Object.entries 的核心特性与边界规范:
| 方法名称 | 返回维度与类型 | 是否包含键名 | 典型适用业务场景 | 最佳搭配 API |
|---|---|---|---|---|
Object.keys() |
string[] (一维) |
仅键名 | 校验属性必填项、表单字段名校验、获取属性数量 | .includes(), .length |
Object.values() |
any[] (一维) |
不包含 | 数据统计聚合、下拉框渲染、批量布尔状态检查 | .reduce(), .some(), .every() |
Object.entries() |
[string, any][] (二维) |
完整键值 | 按条件过滤对象属性、URL 参数拼接、字典结构互转 | Object.fromEntries(), new Map() |
工程最佳实践准则
- 只取所需,避免过度转换:若仅需对数值求和,切勿使用
Object.entries()再解构取值,使用Object.values()无论在内存分配还是代码语义上都更为精简。 - 谨防 null/undefined 引发崩溃:在接收外部 API 响应或组件 Props 时,始终采用防御性传参,如
Object.entries(apiResponse ?? {})。 - 注意数字键的排序效应:依赖对象属性转换数组后的顺序时,需警惕纯数字字符串键的自动升序规则,确保该顺序符合业务预期。
- 善用结构闭环:掌握
Object.entries与Object.fromEntries的组合,是实现非侵入式、纯函数式对象数据清洗(Sanitization)的现代标配方案。
JS中将数组和对象混合组装为JSON字符串
2026-11-05 16:41:42
JS运算符优先级与结合性的区别是什么?
2026-11-05 13:22:02
JS Map怎么只遍历Key或Value
2026-11-05 13:00:36
D3.js 与 ECharts 选型对比:灵活性 vs 开发效率
2026-11-05 09:45:01
为什么JS中typeof []返回object:数组类型检测误区解析
2026-11-04 19:50:47
相关标签:








