所以 ES 6 给我们带来了Maps(而且不会太快)。为了实现我自己的邪恶目的,我希望对 Map 进行子类化,我尝试了以下操作(为了清楚起见,进行了缩写):
function Foo() {
return Map.apply(this, [].slice.call(arguments));
}
var bar = new Foo();
在 V8 环境中,这会引发错误“未使用‘new’调用映射构造函数”。为什么? SpiderMonkey 的理解是“正确的”:
Map.call({}, [['foo', 'bar']]).get('foo');
正如预期的那样,将产生“bar”。在 SpiderMonkey 和 V8 中都尝试类似的事情
function Foo() {};
Foo.prototype = new Map();
var bar = new Foo();
bar.set('foo', 'bar');
将失败:“在不兼容的对象上调用方法集”。所以继承模式就这样出现了。据我所知spec(我没有太多的spec-foo),实际的 Map 对象具有无法访问的内部属性,而这些属性是它们正常工作所需的。但为什么 V8 在第一个模式上抛出错误呢?这似乎是一个奇怪的决定,尤其是当它在 FF 中按预期工作时。
更新:我注意到 FF 和 chrome 都有Object.setPrototypeOf
实施的。万一有人偶然发现这个并想到这一点,我可以告诉你它失败了。以下两项均因不同原因而失败:
//this totally fails, even for custom constructors/objects
var Foo = function(){};
Object.setPrototypeOf(Foo, Map.prototype);
var bar = new Foo(); //bar doesn't have any of the Map properties/methods
//this one has the methods but still throws the 'incompatible object'
//err. Also fails with new Map() instead of Map.prototype
var bar = Object.setPrototypeOf({}, Map.prototype);
TL;DR
扩展地图基本上有四种方法(一些来自下面的答案/评论):
- 向 Map.prototype 添加方法(你真丢脸)。
- 工厂/构造函数使用您委托的内部 Map 实例创建对象
- Mixin fn 将属性复制到 Maps 上:
function Foo(){this.bar = 'boo!'}
var baz = new Map();
Foo.call(baz);
baz.bar; //yields 'boo!'
baz.set('5', 5).get('5'); //yields 5
或者只是等待您关心的 ES6 类登陆平台)