如何提取数组对象到新对象并完善custom对象parent属性的links绑定
It looks like your current code adds the entire default object as the parent to custom items, but doesn't map each custom link to its corresponding default link. To fix this, we need to adjust how we handle the parent links when processing custom data—specifically, matching each custom link to its counterpart in the default item's links and attaching that as the parent for the custom link.
Here's the step-by-step solution:
- Keep the parent reference in custom items: We still want to attach the full default object as a parent to matching custom items, since we need access to its links later.
- Map custom links to their default parent links: When processing each custom link, find the matching link in the parent's links (using
numberas the unique identifier, since it's distinct in your example) and format it with the parent'sidandscope. - Restructure link processing: Use
flatMapfor cleaner array handling, and add logic to inject the formatted parent link into custom links.
Modified code:
const data = { default: [ { id: "first", links: [{ name: "testName1", number: 1 }] }, { id: "second", links: [ { name: "testName2", number: 2 }, { name: "testName2.1", number: 2.1 } ] }, { id: "third", links: [ { name: "testName3", number: 3 }, { name: "testName3.1", number: 3.1 } ] }, ], custom: [ { id: "first", links: [{ name: "testName1", number: 1 }] }, { id: "second", links: [ { name: "testName2", number: 2 }, { name: "testName2.1", number: 2.1 } ] }, ] }; function formattedData() { let defaultData = [...(data.default || [])]; let customData = [...(data.custom || [])]; const customIds = new Set(customData.map(el => el.id)); if (defaultData.length > 0 && customData.length > 0) { // Attach full default object as parent to matching custom items customData = customData.map(cd => { const parent = defaultData.find(dd => dd.id === cd.id); return parent ? { ...cd, parent: { ...parent, scope: "defaultData" } } : cd; }); // Remove default items that have a matching custom id defaultData = defaultData.filter(dd => !customIds.has(dd.id)); } // Process all links, including adding parent links for custom data return Object.entries({ defaultData, customData }) .flatMap(([scopeKey, items]) => { return items.flatMap(item => { const { links, parent, ...itemProps } = item; return links.map(link => { const linkResult = { ...link, ...itemProps, scope: scopeKey }; // Add formatted parent link for custom items with a parent if (scopeKey === 'customData' && parent) { const matchingParentLink = parent.links.find(l => l.number === link.number); if (matchingParentLink) { linkResult.parent = { ...matchingParentLink, id: parent.id, scope: parent.scope }; } } return linkResult; }); }); }); } console.log(formattedData());
Key Changes Explained:
- Set for ID lookups: Using
SetforcustomIdsmakes the filter operation more efficient than arrayincludes. - Parent link matching: For each custom link, we find the corresponding link in the parent's
linksarray usingnumber(adjust this matching logic if you use a different unique identifier for links). - Cleaner array handling:
flatMapreplaces nestedmap+flat(2)for more readable code. - Preserve original data: We spread the original
defaultDataandcustomDatato avoid mutating the input object.
This code will produce the expected output (note: there appears to be a typo in your expected result where one custom link's parent has the wrong name/number—this code will correctly match each custom link to its exact default counterpart).
内容的提问来源于stack exchange,提问作者chikipiki_3443

