如何创建通用select()函数实现任意深度对象属性子集提取与实时重命名
实现通用的对象属性提取与重命名函数
这确实是个非常实用的需求——一个能灵活提取任意深度对象属性、同时支持实时重命名的通用工具,不管是处理单个对象还是批量处理数组都能复用。下面我来给你实现这个select()函数,完全匹配你的预期:
完整实现代码
function select(data, config) { const result = {}; // 遍历配置中的每个新属性名与对应路径 for (const [newPropName, pathArray] of Object.entries(config)) { // 沿着路径数组从原数据中逐层取值,可选链避免中间节点不存在报错 const targetValue = pathArray.reduce((currentObj, key) => { return currentObj?.[key]; }, data); // 将值赋值给新的属性名 result[newPropName] = targetValue; } return result; }
函数工作原理
- 初始化结果对象:创建一个空对象用于存储最终的属性子集。
- 遍历配置项:通过
Object.entries(config)把映射配置转换成键值对数组,每个元素对应「新属性名」和「原属性路径数组」。 - 逐层提取属性:用
reduce遍历路径数组,从原数据对象开始,沿着路径逐步深入嵌套结构。currentObj?.[key]使用可选链操作符,确保如果中间某个节点不存在(比如原数据里没有某个嵌套属性),不会抛出错误,而是返回undefined。 - 赋值重命名:把提取到的值赋值给结果对象的新属性名。
验证你的示例
用你提供的测试数据调用函数:
const earthData = { distanceFromSun: 149280000, continents: { asia: { area: 44579000, population: 4560667108, countries: { japan: { temperature: 62.5 } }, }, africa: { area: 30370000, population: 1275920972 }, europe: { area: 10180000, population: 746419440 }, america: { area: 42549000, population: 964920000 }, australia: { area: 7690000, population: 25925600 }, antarctica: { area: 14200000, population: 5000 }, }, }; const earthDataSubset = select(earthData, { distanceFromSun: ['distanceFromSun'], asiaPop: ['continents', 'asia', 'population'], americaArea: ['continents', 'america', 'area'], japanTemp: ['continents', 'asia', 'countries', 'japan', 'temperature'], });
得到的结果完全符合预期:
{ distanceFromSun: 149280000, asiaPop: 4560667108, americaArea: 42549000, japanTemp: 62.5 }
批量处理对象数组
正如你期望的那样,这个函数可以直接配合map批量处理对象数组:
const earthData2050 = { distanceFromSun: 149280000, continents: { asia: { area: 44579000, population: 4560767108, countries: { japan: { temperature: 73.6 } }, }, africa: { area: 30370000, population: 1275960972 }, europe: { area: 10180000, population: 746419540 }, america: { area: 42549000, population: 964910000 }, australia: { area: 7690000, population: 25928600 }, antarctica: { area: 14200000, population: 5013 }, }, }; const myEarthArr = [earthData, earthData2050]; const mappedResult = myEarthArr.map(record => select(record, { distanceFromSun: ['distanceFromSun'], asiaPop: ['continents', 'asia', 'population'], americaArea: ['continents', 'america', 'area'], japanTemp: ['continents', 'asia', 'countries', 'japan', 'temperature'], }));
返回的批量结果和你硬编码实现的完全一致。
额外优化建议
- 处理不存在的路径:如果原数据中某个路径不存在,函数会给对应新属性赋值
undefined。如果你想跳过这类属性,可以在赋值前加判断:if (targetValue !== undefined) { result[newPropName] = targetValue; } - 支持数组索引:这个函数天然支持路径中包含数组索引,比如路径
['users', 0, 'name']可以提取数组第一个元素的name属性。 - 添加默认值:如果需要给不存在的路径设置默认值,可以修改
reduce逻辑:const targetValue = pathArray.reduce((currentObj, key) => { return currentObj?.[key] ?? '默认值'; }, data);
内容的提问来源于stack exchange,提问作者Emman
相关产品推荐
相关产品推荐

