2

在一次采访中,我被要求实现键/值对的数据结构,其中键可以是一个对象,我知道这可以使用 ES6 映射,但是它们如何在 Javascript 中的引擎盖下工作,其中键被严格字符串化并实现哈希表/对象的相同常量查找时间?

谢谢你。

4

2 回答 2

2

的键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

这些方法在幕后所做的是特定于实现的。

于 2019-10-24T14:30:09.313 回答
1

我在一次采访中被问到这个问题,我无法保证 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 对象中删除该属性即可。有趣而有见地的练习!希望这可以帮助 :)

于 2021-12-21T00:34:11.440 回答