在一次采访中,我被要求实现键/值对的数据结构,其中键可以是一个对象,我知道这可以使用 ES6 映射,但是它们如何在 Javascript 中的引擎盖下工作,其中键被严格字符串化并实现哈希表/对象的相同常量查找时间?
谢谢你。
在一次采访中,我被要求实现键/值对的数据结构,其中键可以是一个对象,我知道这可以使用 ES6 映射,但是它们如何在 Javascript 中的引擎盖下工作,其中键被严格字符串化并实现哈希表/对象的相同常量查找时间?
谢谢你。
的键Map
不是对象的键Map
。它们是.get
和.set
方法的参数。
const map = new Map;
const key = {};
map.set(key, "stuff"); // key is passed as an argument, not stringified
map[key] // key would get stringified here according to language semantics, but even then it would be undefined as maps keys aren't keys of the map object
这些方法在幕后所做的是特定于实现的。
我在一次采访中被问到这个问题,我无法保证 Map 是如何在后台实际实现的(最终在这里寻找自己)。然而,这是我与面试官一起制定的方法(注意,要求仅适用于 DOM 节点键,但我确实认为对象是最难处理的键,其余的可以通过额外的代码轻松处理),我认为它至少是有见地的:
class Map {
constructor() {
this.map = {}; // internal key/value object
this.trackerKey = Symbol();
}
set(key, value) {
let lookupKey = key[this.trackerKey];
if (!lookupKey) {
lookupKey = Symbol();
key[this.trackerKey] = lookupKey;
}
this.map[lookupKey] = value;
}
has(key) {
return key.hasOwnProperty(this.trackerKey);
}
get(key) {
const lookupKey = key[this.trackerKey];
return this.map[lookupKey];
}
delete(key) {
const lookupKey = key[this.trackerKey];
delete key[this.trackerKey];
delete this.map[lookupKey];
}
}
基本上,这个想法是在引擎盖下使用符号来跟踪对象。trackerKey
是我们添加到所有进入的键的(符号)属性。由于它是在实例内部定义的符号,所以没有其他东西可以引用它。
因此,当我们转到 时set
,我们检查对象上是否存在 trackerKey 属性。如果不是,我们将其设置为新符号。然后,我们将内部映射中该键的值设置为传入的值。
has
现在get
是相当简单的查找。我们检查我们的跟踪器密钥是否存在于密钥上,以查看它是否包含在我们的 Map 中。因为get
我们可以简单地从它的 trackerKey 属性中获取对象的内部查找键。
对于delete
,我们只需要从 key 对象中删除 trackerKey 属性,然后在我们内部的 map 对象中删除该属性即可。有趣而有见地的练习!希望这可以帮助 :)