为何JavaScript Map以数字数组为键取值返回undefined?
为什么用数组作为Map的键会返回undefined?
这是一个很典型的JavaScript引用类型陷阱问题,我来给你拆解清楚:
问题核心:引用类型的相等性判断
在JavaScript里,数组属于引用类型,而Map判断键是否相等的规则是基于引用相等性(也就是两个值是否指向内存中的同一个对象),而不是值的内容是否一致。
你在set的时候创建的[1, 0, 0],和get时新创建的[1, 0, 0],虽然内容完全一样,但它们是两个独立的数组对象,在内存中的地址不同。Map会把它们当成完全不同的键,所以自然找不到对应的值,返回undefined。
举个更直观的例子验证一下:
console.log([1,0,0] === [1,0,0]); // 输出false,因为是不同的引用
解决方法
这里有几种常用的方案可以解决这个问题:
1. 将数组转换为字符串作为键(最简便的通用方案)
把数组转成字符串(比如用join(',')或者JSON.stringify),这样相同内容的数组会生成完全相同的字符串,而字符串是值类型,Map会正确识别:
const rule30Map = new Map(); // 存值时转换为字符串 rule30Map.set([1, 0, 0].join(','), 1); rule30Map.set([0, 1, 1].join(','), 1); rule30Map.set([0, 1, 0].join(','), 1); rule30Map.set([0, 0, 1].join(','), 1); // 取值时同样转换 console.log(rule30Map.get([1, 0, 0].join(','))); // 输出1,符合预期
如果数组里包含复杂类型(比如嵌套数组或对象),JSON.stringify会更稳妥,因为join只能处理一维的基本类型数组。
2. 使用同一个数组引用作为键
如果你能提前把键数组保存为变量,后续存值和取值都用这个变量,就能保证引用一致:
const key1 = [1, 0, 0]; const key2 = [0, 1, 1]; const key3 = [0, 1, 0]; const key4 = [0, 0, 1]; const rule30Map = new Map(); rule30Map.set(key1, 1); rule30Map.set(key2, 1); rule30Map.set(key3, 1); rule30Map.set(key4, 1); console.log(rule30Map.get(key1)); // 输出1
这个方法适合键数组不需要动态生成的场景。
3. 自定义支持值相等的Map类(适合频繁处理数组键的场景)
如果你的业务需要大量用数组作为键,可以封装一个自定义Map,内部自动处理键的转换:
class ValueMap extends Map { set(key, value) { // 把数组键转换为JSON字符串,其他类型直接用原键 const processedKey = Array.isArray(key) ? JSON.stringify(key) : key; super.set(processedKey, value); return this; } get(key) { const processedKey = Array.isArray(key) ? JSON.stringify(key) : key; return super.get(processedKey); } } // 使用示例 const rule30Map = new ValueMap(); rule30Map.set([1, 0, 0], 1); console.log(rule30Map.get([1, 0, 0])); // 输出1
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

