在JS中将对象作为另一个对象的属性键时,该键的实际类型是什么?
JavaScript普通对象的属性键本质
普通对象(也就是你用{}声明的对象)的属性键只支持两种类型:字符串、Symbol。任何其他类型的值作为键传入时,都会被自动强制转换为字符串类型,这个转换和内存引用没有任何关系。
你遇到的现象原因
当你把apple1、apple2这类普通对象作为属性键时,JS引擎会自动调用对象的toString()方法获取字符串值,再把这个字符串作为真正的属性键。
普通对象默认的toString()实现固定返回"[object Object]",所以不管你用多少个不同的普通对象作为键,最终转换出来的都是同一个字符串,后面的赋值自然会覆盖前面的赋值。
你可以通过下面的代码验证这个逻辑:
// 两个不同对象的toString返回值完全相同 console.log(apple1.toString()) // 输出 "[object Object]" console.log(apple2.toString()) // 输出 "[object Object]" // 最终orchard里只有一个属性,值是最后一次赋值的2 console.log(orchard[apple1]) // 输出 2 console.log(Object.keys(orchard)) // 输出 ["[object Object]"]
如果需要自定义普通对象转字符串的结果,可以重写对象的toString方法:
const apple3 = { tastes: 'good', toString() { return 'apple3' } } orchard[apple3] = 3 console.log(Object.keys(orchard)) // 输出 ["[object Object]", "apple3"]
用对象作为唯一键的正确方案
如果你需要将对象本身作为唯一标识的键,应该使用ES6新增的Map数据结构,Map的键支持任意JS类型,会直接保留对象的引用作为唯一判断依据,不会做强制类型转换:
const orchardMap = new Map() orchardMap.set(apple1, 1) orchardMap.set(apple2, 2) // 两个对象都被作为独立的键保留 console.log(orchardMap.get(apple1)) // 输出 1 console.log(orchardMap.get(apple2)) // 输出 2 console.log(orchardMap.size) // 输出 2
内容的提问来源于stack exchange,提问作者Don P
相关产品推荐
相关产品推荐

