Map.prototype.size 是只读属性,O(1) 时间返回键值对数量,因底层缓存计数器;对象无内置长度,需遍历且受键类型限制;WeakMap 不支持 size。

Map.prototype.size 是一个只读属性,直接返回 Map 实例中键值对的数量,时间复杂度为 O(1) —— 它不遍历、不计算,只是读取内部维护的计数器。
为什么 size 属性能“秒出结果”?
Map 在底层实现中(如 V8 引擎)会持续跟踪插入、删除操作,并实时更新一个内部长度字段。每次调用 map.size,引擎只需返回这个已缓存的数值,无需访问任何键或值,也不触发迭代逻辑。
对比之下:
- 对象(
{})没有内置长度属性,必须靠Object.keys(obj).length或手动for...in遍历才能统计可枚举属性个数; - 这些方法需构建新数组(
Object.keys)或逐个检查每个属性(含原型链判断),时间复杂度至少是 O(n),且可能受属性枚举顺序、不可枚举属性、Symbol 键等干扰。
Map.size 不受键类型影响
Map 允许任意类型作键(函数、对象、Symbol、null 等),而对象只能用字符串或 Symbol(且 Symbol 键不会被 Object.keys 捕获)。若你的数据含非字符串键,用对象模拟 Map 时连“准确计数”都做不到,更别说效率了。
例如:
const map = new Map();map.set({}, 'a');
map.set(function(){}, 'b');
console.log(map.size); // 2 ✅
const obj = {};
obj[{}] = 'a'; // 转成 "[object Object]"
obj[function(){}] = 'b'; // 也转成 "[object Function]"
console.log(Object.keys(obj).length); // 1 ❌(键被覆盖)
什么时候不能依赖 size?
size 始终反映当前 Map 的真实项数,但它不保证键值对的“有效性”或“业务意义”。比如你存了 map.set('id', null),size 仍算作 1。若业务上需要“非空值数量”,仍需遍历过滤。
另外:size 对 WeakMap 不可用(WeakMap 无 size 属性),因其设计目标就是避免暴露引用数量,防止内存分析攻击。
实际建议
- 需要频繁查长度 + 支持任意键类型 → 优先用 Map,直接读
.size; - 仅需字符串键 + 简单结构 → 普通对象够用,但计数请接受
Object.keys(obj).length的开销; - 做性能敏感循环(如渲染列表前判断非空)→
map.size > 0比map.keys().next().done === false更快更简洁; - 避免误用:
new Map([[1,2],[3,4]]).size是 2,不是 4 —— 它统计的是键值对个数,不是元素总数。










