JavaScript中Object与Map对象的差异及键类型转换疑问
Hey there! Let's clear up your confusion first, then dive into the core differences between JavaScript Objects and Maps.
First: The Quirk in Your Test Code
Looking closely at your code, there's a small detail that's throwing off the results: you're storing different value types in the Map vs. the Object for the keyFunc key:
// Map stores a STRING value m.set(keyFunc, 'function'); // Object stores a FUNCTION value obj[keyFunc] = function() {};
That's why typeof m.get(keyFunc) returns string (you're grabbing the string 'function') and typeof obj[keyFunc] returns function (you're grabbing the actual function). If you update the Map to store the function instead of the string:
m.set(keyFunc, function() {});
Then typeof m.get(keyFunc) will correctly return function—Map isn't converting your keys to strings here at all.
Core Differences Between Object and Map
Now let's break down the real distinctions between these two structures:
Allowed Key Types
- Object: Keys can only be strings or Symbols. Any other type (like objects, functions, numbers) gets automatically converted to a string via its
toString()method. For example, when you useobj[keyObj], you're actually usingkeyObj.toString()(which is"[object Object]") as the key. This means two different empty objects will act as the same key in an Object. - Map: Keys can be any type—objects, functions, primitives, you name it. Reference types (like objects) are compared by their actual reference, not a string representation. So two distinct empty objects will count as separate keys in a Map.
- Object: Keys can only be strings or Symbols. Any other type (like objects, functions, numbers) gets automatically converted to a string via its
Key Order & Iteration
- Object: While ES6+ preserves insertion order for string/Symbol keys, numeric keys are sorted and placed first. Iterating requires workarounds like
Object.keys()orfor...in(which also loops over prototype properties if you don't filter them). - Map: Maintains strict insertion order for all keys. It's also iterable by default, so you can use
for...ofdirectly, or the built-inforEach()method for clean, straightforward iteration.
- Object: While ES6+ preserves insertion order for string/Symbol keys, numeric keys are sorted and placed first. Iterating requires workarounds like
Size Tracking
- Object: To get the number of key-value pairs, you have to calculate it manually (e.g.,
Object.keys(obj).length). - Map: Has a built-in
sizeproperty that gives you the count instantly.
- Object: To get the number of key-value pairs, you have to calculate it manually (e.g.,
Prototype Interference
- Object: Inherits properties from
Object.prototype(liketoString,hasOwnProperty), which can cause conflicts if you use those names as keys. - Map: Has no prototype chain, so all keys in a Map are exactly the ones you've added—no unexpected built-in properties.
- Object: Inherits properties from
Performance
- Object: Optimized for static datasets where you don't add/remove keys frequently.
- Map: Performs better for dynamic use cases with frequent additions or deletions of key-value pairs.
Example to Demonstrate Key Reference Behavior
Here's a quick snippet to show how Map handles object keys differently from Object:
const obj = {}; const map = new Map(); const key1 = { id: 1 }; const key2 = { id: 1 }; // Same structure, different reference obj[key1] = 'value'; map.set(key1, 'value'); console.log(obj[key2]); // 'value' — because key1 and key2 both convert to "[object Object]" console.log(map.get(key2)); // undefined — because key1 and key2 are distinct references
内容的提问来源于stack exchange,提问作者Roman Azimi

