如何基于可用键规则和用户输入构建合规的合并JavaScript对象
基于规则补全嵌套对象的JavaScript实现方案
需求说明
1. 可用键规则
[ "cars[].model", "cars[].make", "cars[].year", "toys.color", "toys.type[].brand", "toys.type[].price", "id", "books[].publisher[].authors[]" ]
其中cars[].model表示cars为对象数组,model是数组元素的属性之一。
2. 输入对象示例
{ "cars": [ { "make": "Audi" }, { "model": "A8", "year": "2007" } ], "id": "xyz", "extra": "test", "toys": { "color": "Black", "type": [ { "price": "$100" } ] } }
3. 输出规则
- 规则中定义的字段如果在输入中不存在,对应值设为空:普通字符串类型为空字符串,数组类型为空数组
- 输入中不在规则里的额外字段直接保留
期望输出示例:
{ "cars": [ { "model": "", "make": "Audi", "year": "" }, { "model": "A8", "make": "", "year": "2007" } ], "toys": { "color": "Black", "type": [ { "brand": "", "price": "$100" } ] }, "id": "xyz", "books": [ { "publisher": [ { "authors": [] } ] } ], "extra": "test" }
实现思路
- 先把路径规则解析为结构化Schema,标记每个节点是否为数组类型
- 深拷贝原始输入对象,保留所有额外字段
- 递归遍历Schema,逐层补全目标对象的缺失字段:
- 数组类型字段不存在时,初始化包含默认结构的数组;存在则遍历所有元素补全内部属性
- 对象类型字段不存在时初始化空对象,再补全所有定义的子属性
- 基础类型字段缺失时赋值为空字符串,规则末尾标记为数组的字段默认赋值为空数组
完整代码实现
// 解析路径规则生成Schema function parseRules(rules) { const schema = {}; rules.forEach(rule => { const parts = rule.split('.'); let current = schema; parts.forEach((part, idx) => { const isArray = part.endsWith('[]'); const key = isArray ? part.slice(0, -2) : part; if (!current[key]) { current[key] = { isArray, children: {} }; } if (idx !== parts.length - 1) { current = current[key].children; } }); }); return schema; } // 递归补全对象字段 function fillSchema(obj, schema) { Object.entries(schema).forEach(([key, def]) => { // 处理数组类型 if (def.isArray) { // 没有值的话初始化数组,默认加一个空元素补结构 if (!obj[key] || !Array.isArray(obj[key])) { obj[key] = [{}]; } // 遍历每个数组元素补全子字段 obj[key].forEach(item => { if (Object.keys(def.children).length > 0) { fillSchema(item, def.children); } else { // 规则末尾是数组的情况,比如authors[] if (!Array.isArray(item)) obj[key] = []; } }); return; } // 处理对象类型 if (Object.keys(def.children).length > 0) { if (!obj[key] || typeof obj[key] !== 'object') { obj[key] = {}; } fillSchema(obj[key], def.children); return; } // 处理基础类型,缺失设为空字符串 if (obj[key] === undefined) { obj[key] = ''; } }); return obj; } // 主方法 function mergeObjectByRules(input, rules) { // 深拷贝输入,保留所有原始字段 const target = JSON.parse(JSON.stringify(input)); const schema = parseRules(rules); return fillSchema(target, schema); } // 测试用例 const rules = [ "cars[].model", "cars[].make", "cars[].year", "toys.color", "toys.type[].brand", "toys.type[].price", "id", "books[].publisher[].authors[]" ]; const input = { "cars": [ { "make": "Audi" }, { "model": "A8", "year": "2007" } ], "id": "xyz", "extra": "test", "toys": { "color": "Black", "type": [ { "price": "$100" } ] } }; console.log(JSON.stringify(mergeObjectByRules(input, rules), null, 2));
运行上述代码输出结果与需求中的期望输出完全一致。
内容的提问来源于stack exchange,提问作者Sandy_22
相关产品推荐
相关产品推荐

