JavaScript:修复mapById函数,实现对象数组转ID为键的映射对象
mapById Function: Accumulating Object Key-Value Pairs Great question! Let's walk through what's going wrong and how to fix it, plus answer your follow-up questions clearly.
What's the Issue with Your Current Code?
You nailed the root problem: inside your forEach loop, you’re declaring a new local obj variable every time with var obj = {[objectKey]: item};. This new variable has no connection to the empty obj you initialized at the top of the function—so the original object never gets updated, and you end up returning either that empty object (if you kept the var) or just the last item (if you accidentally omitted var and overwrote the outer obj each time).
How to Add Key-Value Pairs to an Object (Like Array push)
You don’t need a fancy method like push for objects—direct property assignment is the equivalent way to "append" entries. Just use bracket notation to assign to your existing object:
obj[yourKey] = yourValue;
This adds the key-value pair to the object (or overwrites the value if the key already exists, which makes sense here since each id should be unique).
Also, a quick best practice: using Object.values(item)[0] to grab the id is risky—JavaScript doesn’t guarantee property order in all scenarios, so if an object’s first property ever isn’t id, your code breaks. Just use item.id directly since your input objects explicitly have this property.
Fixed Version of Your Original Code
Here’s how to adjust your function to accumulate all items correctly:
function mapById(list) { var obj = {}; list.forEach(function(item) { // Assign directly to the outer obj variable, no re-declaration obj[item.id] = item; }); return obj; }
A More Concise Alternative: Array.reduce
For tasks where you turn an array into a single value (like an object), JavaScript’s reduce method is tailor-made. It’s more idiomatic and concise for this kind of accumulation:
function mapById(list) { return list.reduce(function(accumulator, item) { accumulator[item.id] = item; return accumulator; }, {}); // Start with an empty object as the initial accumulator }
This does exactly the same work as your forEach version but in a cleaner, functional-style way.
Do You Need a Closure?
Nope! The problem here was purely about variable scope (re-declaring obj inside the loop instead of using the outer one). Closures are useful for preserving state between function calls, but they’re totally unnecessary here.
Testing this with your input example will give you exactly the output you want:
var input = [{id: 102, name: "Alice"}, {id: 205, name: "Bob", title: "Dr."}, {id: 592, name: "Claire", age: 32}]; console.log(mapById(input)); // Output: {102: {id: 102, name: "Alice"}, 205: {id: 205, name: "Bob", title: "Dr."}, 592: {id: 592, name: "Claire", age: 32}}
内容的提问来源于stack exchange,提问作者cocomatt

