尝试在ES6 Maps上摆脱自定义get / set功能。目前正在使用Babel将我的代码转换为ES5。
Chrome Version 41.0.2272.101 m
class MyMap extends Map {
get(key) {
if (!this.has(key)) { throw new Error(...); }
return super.get(key);
}
set(key) {
if (this.has(key)) { throw new Error(...); }
return super.set(key);
}
}
我不确定我的语法是否错误,或者我错过了某种类型的实现。但是我收到以下错误:
方法Map.prototype.forEach调用不兼容的接收器
答案 0 :(得分:10)
Babel明确表示他们不支持扩展内置类。见http://babeljs.io/docs/usage/caveats/#classes。但是,原因并不像“ES5中的限制”那么简单,因为Map
不是ES5的特性。似乎Map的实现不支持基本模式,例如
Map.prototype.set.call(mymap, 'key', 1);
这实际上是Babel在这种情况下生成的内容。问题是包含V8的Map的实现过于严格,并检查this
调用中的Map.set.call
是否恰好是Map,而不是在其原型链中使用Map。
同样适用于Promise。
答案 1 :(得分:1)
你应该使用旧的方式:
function ExtendedMap(iterable = []) {
if (!(this instanceof ExtendedMap)) {
throw new TypeError("Constructor ExtendedMap requires 'new'");
}
const self = (Object.getPrototypeOf(this) === Map.prototype)
? this
: new Map(iterable);
Object.setPrototypeOf(self, ExtendedMap.prototype);
// Do your magic with `self`...
return self;
}
util.inherits(ExtendedMap, Map);
Object.setPrototypeOf(ExtendedMap, Map);
ExtendedMap.prototype.foo = function foo() {
return this.get('foo');
}
然后像往常一样使用new
:
const exMap = new ExtendedMap([['foo', 'bar']]);
exMap instanceof ExtendedMap; // true
exMap.foo(); // "bar"
请注意,ExtendedMap
构造函数会忽略任何不是this
的{{1}}绑定。
答案 2 :(得分:1)
或者,您可以在MapWrapper对象中组成Map()类,并公开自己的API。对象组合的概念在5年前使用得并不多,因此,问题和答案与继承联系在一起并纠结在一起。
答案 3 :(得分:0)
是的,直到Proxies全力以赴,实现你想要做的事情的唯一方法是自己遮蔽地图/集等上的内置方法。
例如,如果您的地图如此:
var myMap = new Map([ ['key1', 'value1'], ['key2', 'value2']])
你必须有一些包装器来传递它以添加内置方法,例如对于get / set:
function proxify(obj){
var $fnMapGet = function(key){
console.log('%cmap get', 'color:limegreen', 'key:', key)
if(!Map.prototype.has.call(this, key)){
throw(new Error('No such key: '+ key))
} else {
return Map.prototype.get.call(this, key)
}
}
var $fnMapSet = function(key, value){
console.log('%cmap set', 'color:tomato', 'key:', key, 'value:', value)
if(Map.prototype.has.call(this, key)){
throw(new Error('key is already defined: ' + key))
} else {
if(Map.prototype.get.call(this, key) == value){
console.log('%cmap set', 'color:tomato', '*no change')
return this
}
return Map.prototype.set.call(this, key, value)
}
}
Object.defineProperty(obj, 'get', {
get(){
return $fnMapGet
}
})
Object.defineProperty(obj, 'set', {
get(){
return $fnMapSet
}
})
return obj
}
那么:
proxify(myMap)
myMap.get('key1') // <= "value1"
myMap.get('key2') // <= "value2"
myMap.get('key3') // <= Uncaught Error: No such key: key3
myMap.set('key3', 'value3') // <= Map {"key1" => "value1", "key2" => "value2", "key3" => "value3"}
myMap.set('key3', 'another value3') // <= Uncaught Error: key is already defined: key3
这会增加在地图上做自己的自定义set / get的能力,不像子类Map那么好,也不像es6代理那么简单,但它至少可以工作。
以下运行的完整代码段:
var myMap = new Map([ ['key1', 'value1'], ['key2', 'value2']])
function proxify(obj){
var $fnMapGet = function(key){
console.log('get key:', key)
if(!Map.prototype.has.call(this, key)){
throw(new Error('No such key: '+ key))
} else {
return Map.prototype.get.call(this, key)
}
}
var $fnMapSet = function(key, value){
console.log('set key:', key, 'value:', value)
if(Map.prototype.has.call(this, key)){
throw(new Error('key is already defined: ' + key))
} else {
if(Map.prototype.get.call(this, key) == value){
console.log('*no change')
return this
}
return Map.prototype.set.call(this, key, value)
}
}
Object.defineProperty(obj, 'get', {
get(){
return $fnMapGet
}
})
Object.defineProperty(obj, 'set', {
get(){
return $fnMapSet
}
})
return obj
}
proxify(myMap)
myMap.get('key1')
myMap.get('key2')
try {
myMap.get('key3')
} catch(ex){
console.warn('error:', ex.message)
}
myMap.set('key3', 'value3')
try {
myMap.set('key3', 'another value3')
} catch(ex){
console.warn('error:', ex.message)
}
答案 4 :(得分:-1)
不幸的是,Babel不支持它。奇怪的是,您可以在控制台中运行以下命令:
clear();
var Store = function Store(data) {
// var _map = new Map(data);
this.get = function get(key) {
console.log('#get', key);
return S.prototype.get.call(S.prototype, key); // or return _map.get(key);
};
this.set = function set(key, value) {
S.prototype.set.call(S.prototype, key, value); // or _map.set(key, value);
return this;
};
};
Store.prototype = new Map(); // we could just wrap new Map() in our constructor instead
var s = new Store();
s.set('a', 1);
s.get('a');
但是,使用Babel执行以下操作是没用的:
class Store extends Map {
constructor(...args) {
super(...args);
return this;
}
}
尝试拨打(new Store(['a','1'])).get('a')
时会出错。令我感到震惊的是,像巴贝尔的人们完全不理解Map
这样重要的事情。
这是我推荐的。 我多年来一直在做的事情 创建一个JavaScript类,您可以随身携带任何演出或项目。称之为“Dictionary
”,如果您的环境支持Map
,并且您需要一张地图,只需打包Map
- 以提高性能。如果您需要继承Map
,请继承Dictionary
。我实际上有自己的私人回购与各种算法&amp;我随处可见的数据结构,但你也可以找到完成同样事情的公共回购。有点痛苦,但是这样你并不是每个框架都依赖同样的东西100%环境。