我有一个简单的案例: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
}
最不优雅的解决方案,因为我不仅要实现get
和set
,还要实现所有的地图功能。此外,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}}的方式是正确而强大的方式?
答案 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());