Javascript 有没有办法冻结ES6地图?
我正在寻找一种冻结本地ES6地图的方法 而且似乎不起作用:Javascript 有没有办法冻结ES6地图?,javascript,hashmap,ecmascript-6,immutability,Javascript,Hashmap,Ecmascript 6,Immutability,我正在寻找一种冻结本地ES6地图的方法 而且似乎不起作用: let myMap = new Map([["key1", "value1"]]); // Map { 'key1' => 'value1' } Object.freeze(myMap); Object.seal(myMap); myMap.set("key2", "value2"); // Map { 'key1' => 'value1', 'key2' => 'value2' } 由于冻结冻结对象和映射的属性
let myMap = new Map([["key1", "value1"]]);
// Map { 'key1' => 'value1' }
Object.freeze(myMap);
Object.seal(myMap);
myMap.set("key2", "value2");
// Map { 'key1' => 'value1', 'key2' => 'value2' }
由于冻结冻结对象
和映射
的属性不是对象
,这是预期的行为吗?或者这可能是一个错误/尚未实现
是的,我知道,我可能应该使用,但是有没有办法用本机ES6映射实现这一点呢?没有,您可以编写一个包装器来实现这一点
Object.freeze
锁定对象的属性,但是当Map
实例是对象时,它们存储的值不是属性,所以冻结对它们没有影响,就像隐藏内部状态的任何其他类一样
在支持扩展内置项的真实ES6环境中(而不是Babel),您可以执行以下操作:
class FreezableMap extends Map {
set(...args){
if (Object.isFrozen(this)) return this;
return super.set(...args);
}
delete(...args){
if (Object.isFrozen(this)) return false;
return super.delete(...args);
}
clear(){
if (Object.isFrozen(this)) return;
return super.clear();
}
}
如果您需要在ES5环境中工作,您可以轻松地为Map
创建一个包装器类,而不是扩展Map
类。,您的回答给了我一个想法,那么:
function freezeMap(myMap){
if(myMap instanceof Map) {
myMap.set = function(key){
throw('Can\'t add property ' + key + ', map is not extensible');
};
myMap.delete = function(key){
throw('Can\'t delete property ' + key + ', map is frozen');
};
myMap.clear = function(){
throw('Can\'t clear map, map is frozen');
};
}
Object.freeze(myMap);
}
这对我来说非常有效:)
更新了评论中的要点:
var mapSet = function(key){
throw('Can\'t add property ' + key + ', map is not extensible');
};
var mapDelete = function(key){
throw('Can\'t delete property ' + key + ', map is frozen');
};
var mapClear = function(){
throw('Can\'t clear map, map is frozen');
};
function freezeMap(myMap){
myMap.set = mapSet;
myMap.delete = mapDelete;
myMap.clear = mapClear;
Object.freeze(myMap);
}
对不起,我无法发表评论。我只是想添加我的typescript变体
const mapSet = function (key: unknown) {
throw "Can't add property " + key + ', map is not extensible';
};
const mapDelete = function (key: unknown) {
throw "Can't delete property " + key + ', map is frozen';
};
const mapClear = function () {
throw 'Can\'t clear map, map is frozen';
};
function freezeMap<T extends Map<K, V>, K, V>(myMap: T) {
myMap.set = mapSet;
myMap.delete = mapDelete;
myMap.clear = mapClear;
Object.freeze(myMap);
return myMap;
}
const映射集=函数(键:未知){
抛出“无法添加属性”+键+”,映射不可扩展“;
};
const mapDelete=函数(键:未知){
抛出“无法删除属性”+键+”,映射被冻结“;
};
常量mapClear=函数(){
抛出“无法清除地图,地图已冻结”;
};
函数冻结图(myMap:T){
myMap.set=mapSet;
myMap.delete=mapDelete;
myMap.clear=mapClear;
对象冻结(myMap);
返回myMap;
}
相关:(我最初认为你的问题是重复的,但在没有Map
的情况下搜索问题之前,我找不到任何问题)…但当然,这不会阻止任何人做Map.prototype.clear.call(假定为冻结图)
@Bergi True,我假设目标是避免意外突变,而不是真正冻结。为此,您需要使用包装器类。目标确实是避免测试过程中的意外变异。但实际上使用巴别塔。。我将再看一眼,看看是否可以将整个代码库迁移到immutable。谢谢虽然我喜欢静默返回的想法,但最好模拟原始返回类型,因此对于set(),this
,false
(?)用于delete(),而undefined
用于clear。我建议使用isExtensible,而不是IsFrozed。尽管冻结似乎是表面上更好的概念匹配,[[MapData]]的“伪属性”永远无法参与TestIntegrityLevel之类的算法-至少[[IsExtensible]]只涉及布尔标志。考虑:Object.isfreeze(Object.seal(新映射([[1,2]]))
为true,但Object.isfreeze(Object.seal(Object.assign(新映射([[1,2]]),{x:1}))为false。冻结/密封主要描述属性描述符的状态,这一事实使得以这种方式应用属性描述符的尝试有些奇怪。看起来不错,尽管我已经省略了您所称的冻结映射检查的实例。您可以在外部缓存这些方法(以获得极小的内存空间改进),而不是为每次调用重新创建它们。当然,它仍然存在与logan解决方案相同的“缺陷”,不阻止Map.prototype.clear.call(myMap)
。这些都不重要,但你问我的想法:-)公平点!一直在寻求改进,所以谢谢:)。是的,那个“缺陷”仍然存在,但对我来说没什么大不了的,因为我将只在测试中使用它。mapClear
应该没有参数。你不能通过Map.prototype.set.call(myMap,'key,'value')
来克服这个问题吗?我测试过了,你可以用这种方法通过冻结功能。要实际生成冻结视图,需要返回一个对象包装器,该包装器仅通过捕获引用底层映射,并仅提供读取方法。