如何正确扩展ES6 Map

时间:2017-10-19 16:57:58

标签: javascript dictionary ecmascript-6

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

Map是一个内置对象,所以我不确定这样做是否会有任何警告。我试图搜索子类Map是否正确,并得到不一致的结果:不清楚是否允许规范,浏览器/ node.js版本支持它,以及可能产生的副作用(以及测试的内容)。

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

1)对它进行子类化。我已经完成了,似乎就像它有效一样。

class CustomMap extends Map{
    get(key){
        super.get(key);
    }
    set(key, value){
        super.set(key, value);
    }
}

问题:互联网上的很多文章都说你可能会因扩展内置对象而遇到麻烦。大多数是2016年初,现在是2017年末,在Chrome 61中测试。也许现在它是一种安全且受支持的方式吗?

2)制作包装器对象

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的实例。

3)使用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扩展{{1}}的方式是正确而强大的方式?

4 个答案:

答案 0 :(得分:4)

  

目前尚不清楚规范是否允许

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

进行扩展
  

目前还不清楚是什么浏览器/ node.js版本支持它

他们需要本地支持ES6类和Map。使用转换器通常会破坏它。

  

1)对它进行子类化。我已经完成了,看起来它确实有效。

是的,这是正确的方法。

  

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

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

  

制作包装器对象

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

  

3)使用ES6代理 - 将代理应用于某些内置类型是不可取的。

确实,this doesn't work或者至少是笨重的。

答案 1 :(得分:2)

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

答案 2 :(得分:0)

覆盖方法怎么样?

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

答案 3 :(得分:0)

您可以使用扩展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());