JavaScript 是否对 Map 和 Set 使用哈希表?

Ram*_*hum 11 javascript python dictionary hashtable set

我是一名 Python 开发人员,在 JavaScript 中迈出了第一步。

我开始使用MapSet。它们似乎dictsetPython 中的和具有相同的 API ,所以我假设它们是一个哈希表,我可以依靠 O(1) 查找时间。

但是,出于好奇,我尝试看看如果我在 Chrome 的控制台中执行此操作会发生什么:

new Set([new Set([1, 2, 3])])
Run Code Online (Sandbox Code Playgroud)

发生的事情是这样的:

Set(1) {Set(3)}
Run Code Online (Sandbox Code Playgroud)

JavaScript 愉快地创建了集合。怎么会这样?在 Python 中,你会得到一个错误,因为你不能把一个可变项目放在一个集合或一个字典中。为什么 JavaScript 允许它?

jua*_*aga 7

考虑以下 JS 代码:

> m1 = new Map([['a', 1]])
Map { 'a' => 1 }
> m2 = new Map()
Map {}
> m2.set(m1, 3)
Map { Map { 'a' => 1 } => 3 }
> m2.get(m1)
3
Run Code Online (Sandbox Code Playgroud)

但请注意,它是基于身份的散列,即===,所以......

> m2.get(new Map([['a',1]]))
undefined
Run Code Online (Sandbox Code Playgroud)

真的,这张地图有多大用处?

请注意,这与 Python 的默认行为没有什么不同。用户定义类型的默认状态是可散列的:

>>> class Foo: pass
...
>>> f0 = Foo()
>>> s = {f0}
>>> Foo() in s
False
>>> f0 in s
True
Run Code Online (Sandbox Code Playgroud)

在 Python 中,默认情况下,object.__eq__将基于身份进行比较,所以上面的没问题。但是,如果您覆盖__eq__,默认情况下__hash__设置为None并尝试使用基于散列的容器将失败:

>>> class Bar:
...    def __init__(self, value):
...       self.value = value
...    def __eq__(self, other):
...       return self.value == other.value
...
>>> b0 = Bar(0)
>>> b1 = Bar(2)
>>> {b0, b1}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'Bar'
Run Code Online (Sandbox Code Playgroud)

在这一点上,您必须实现__hash__与 一致__eq__,但请注意,您的用户定义对象从来都不是非常“不可变”