Map.has和Map.get性能?
经常使用Map总是会在想要不要用has?看题解总是能看到,但自己个人感觉不是必要的,因此探讨一下:
文档: ECAMScript
Map.prototype.get ( key )
Map.prototype.has( key )
上图来自文档中
这里大致讲解一下意思:
令M为this
值,检查Type(M)===Object
, 如果不是则直接抛出异常
map.set.call(null, 'key', 10); // TypeError
如果是Object但没有内部插槽,依然抛出异常(很多情况下对象都有自己的internal slot,例如Set)
const proxy = new Proxy(map, {});
proxy.set('test', 1); // TypeError
// 解决方案
const proxy = new Proxy(map, {
get(target, prop, receiver) {
// prop为set,获取到 map.set
const value = Reflect.get(...arguments);
return typeof value === 'function' ? value.bind(target) : value;
},
});
后面的操作可以理解为查找,最终检查是否有[[key]]
,且SameValueZero(p.[[key]],key)
这里说明一下
SameValueZero
, 首先JS中有SameValue判断,就是Object.is(a,b),基本上大部分判断都是符合直觉的,有一个地方不同:认为+0和-0是不一样的。
即Object.is(0,-0) // false
SameValueZero则是和SameValue规则相同的情况下,+0与-0也是一致的比较。map,set中key的比较都使用这种规则。
过去看到实例代码等一直以为has是否比get快得多,都是先用has判断再get来尽可能减少get的调用次数。但得出结论并不是。
因此在写算法中遍历数组或者字符串收集信息存入哈希表等情况时,个人喜欢如下写法1。
for (const item of xxx) {
const value = (map.get(item) ?? 0) + 1;
map.set(item, value);
// 过去常看到的写法
if (map.has(item)) {
map.set(item,map.get(item)+1);
}
}
Map.prototype.has()使用
那么是否根本没有使用has的必要?也不是。
目前发现有特别情况下需要使用:key或value是一个falsy值
, 例如就像上面的情况中,使用了??
来规避除undefined与null的其他falsy值,但如果key本身就是存在的(例如有一个key 'x'
的value是undefined),由于我这个判断我会认为这个x
不存在。或者在key是一个falsy值的情况下可能也会导致一些潜在的误判?
因此map.has(key) 可以理解为比较严谨的判断是否真的有此key。
就跟使用'prop' in object
或 object['prop']
,并不能严谨的判断obj
是否真的有prop而不是继承的,严谨的方法应该使用Object.prototype.hasOwnProperty(prop)
就到这里吧,只是浅谈,如有不对感谢评论指正!