Javascript 有没有办法冻结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' } 由于冻结冻结对象和映射的属性

我正在寻找一种冻结本地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' }
由于冻结冻结
对象
映射
的属性不是
对象
,这是预期的行为吗?或者这可能是一个错误/尚未实现


是的,我知道,我可能应该使用,但是有没有办法用本机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')
来克服这个问题吗?我测试过了,你可以用这种方法通过冻结功能。要实际生成冻结视图,需要返回一个对象包装器,该包装器仅通过捕获引用底层映射,并仅提供读取方法。