【问题标题】:How to properly extend ES6 Map如何正确扩展 ES6 Map
【发布时间】:2018-03-31 19:13:16
【问题描述】:

我有一个简单的案例:一个 ES6 Map,我需要给它添加自定义的 get()set()

但是Map 是一个内置对象,所以我不确定这样做是否有任何警告。我试图搜索将Map 子类化是否正确,但结果不一致:尚不清楚规范是否允许,哪些浏览器/node.js 版本支持它,以及可能的副作用(和测试覆盖什么)。

据我了解,扩展Map 功能的主要方法有以下三种:

  1. 子类化它。我已经完成了,它似乎可以工作。
class CustomMap extends Map{
    get(key){
        return super.get(key);
    }
    set(key, value){
        return super.set(key, value);
    }
}

它的问题:Internet 上的很多文章都指出,扩展内置对象可能会遇到麻烦。大多数是 2016 年初,现在是 2017 年底,在 Chrome 61 中进行测试。也许现在这是一种安全且受支持的方式?

  1. 制作包装对象
const Wrapper = function(){
    this._map = new Map();
    this.get = (key) => {return this._map.get(key);}
    this.set = (key, value) => {this._map.set(key, value);}
    ... everything else
}

最不优雅的解决方案,因为我不仅需要实现getset,还需要实现所有地图功能。此外,Wrapper 不是Map 的实例。

  1. 使用 ES6 代理
const ProxyMap = function(){
    return new Proxy(new Map(), {
        get(target, key){
            return target.get(key)
        }
        set(target, key, value){
            target.set(key, value);
        }
    }
}

与扩展类一样,不建议将Proxy 应用于某些内置类型。但同样,自从引入Proxy 规范以来已经过去了很多时间;也许现在Map 可以在现代浏览器中代理?

那么,问题是:在 2017 年,哪种扩展 Map 的方式是正确且稳健的方式?

【问题讨论】:

  • “网上很多文章说扩展内置对象会遇到麻烦” 也许你指的是扩展内置对象在 Babel 中没有得到很好的支持,因为 ES5 不支持它。
  • 网上有人昨天有人告诉我不要吃巧克力一样有帮助,这可能并不意味着巧克力不好吃跨度>
  • 关于扩展内置对象的警告是关于向Array.prototypeObject.prototype等添加其他内置对象的内容。

标签: javascript dictionary ecmascript-6


【解决方案1】:

尚不清楚规范是否允许

是的。从 ES6 开始,所有内置类型都可以使用 class 语法进行扩展

尚不清楚哪些浏览器/node.js 版本支持它

他们需要原生支持 ES6 类和 Map。使用转译器通常会破坏它。

1) 子类化它。我已经完成了,它似乎有效。

是的,这是正确的方法。

Internet 上的很多文章都指出,扩展内置对象可能会遇到麻烦。大多数是 2016 年初,现在是 2017 年末,在 Chrome 61 中进行测试。

我不知道,主要参考 http://perfectionkills.com/extending-native-builtins/ 来自 2011 年。这些文章通过“扩展内置”意味着不同的东西:用自定义对象修改他们的原型对象,例如Map.prototype.getWithDefault = function(…) { … };。他们不引用class … extends …

制作一个包装对象

这也应该没问题。我认为您不一定需要您的实例为instanceof Map,如果您这样做,您必须遵循Liskov substitution principle。并非键值集合的所有“扩展”都适合。

3) 使用 ES6 Proxy - 不建议将 Proxy 应用于某些内置类型。

确实,this doesn't work 或者至少很麻烦。

【讨论】:

  • 并非所有键值集合的“扩展”都适合。“扩展”是什么意思? k/v 集合是否意味着字典(例如Map {Number: Boolean} 类型)?
  • @ftor 是的,字典/maps/hashes/accociative-arrays/whatever-you-wanna-call-them。我可以想象不遵循 LSP 的自定义实现。例如。多地图不应该是地图的子类。
【解决方案2】:

您可以使用扩展 Map 的类来使用您的第一种方法。

例如,以下是扩展Map 的队列(FIFO 结构)的实现,它允许您在 JavaScript 中以 O(1) 的时间复杂度管理队列的插入和删除:

class MyQueue extends Map {
  constructor() {
    super();
    this.insertionIndex = 0;
    this.removalIndex = 0;
  }

  queue(element) {
    this.set(this.insertionIndex, element);
    this.insertionIndex++;
  }

  dequeue() {
    const el = this.get(this.removalIndex);
    this.delete(this.removalIndex);
    if (el) {
      this.removalIndex++;
    }
    return el;
  }
}

const q = new MyQueue();
q.queue(1);
q.queue(2);
console.log(q.dequeue());
console.log(q.dequeue());
q.queue(3);
console.log(q.dequeue());
console.log(q.dequeue()); // now is empty so dequeue will return undefined with no errors
q.queue(4);
console.log(q.dequeue());

【讨论】:

    【解决方案3】:

    第一个是要走的路。 ES6 支持类语法,Maps 和扩展 Maps 也是这个初始定义的一部分。所以每个支持地图的系统都支持第一种方法,而第二种和第三种方法很丑(关于性能等)

    【讨论】:

      【解决方案4】:

      重写方法怎么样?

      m = new Map()
      m.set('x', 2)
      m.get('x')
      => 2
      Map.prototype.get = (x) => 'lalala'
      m.get('x')
      => lalala
      

      【讨论】:

      猜你喜欢
      • 2018-02-26
      • 2015-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多