有没有办法冻结ES6地图?

Tie*_*eme 16 javascript hashmap immutability ecmascript-6

我正在寻找一种方法来冻结原生ES6地图.

Object.freeze并且Object.seal似乎不起作用:

let myMap = new Map([["key1", "value1"]]);
// Map { 'key1' => 'value1' }

Object.freeze(myMap);
Object.seal(myMap);

myMap.set("key2", "value2");
// Map { 'key1' => 'value1', 'key2' => 'value2' }
Run Code Online (Sandbox Code Playgroud)

这是预期的行为,因为冻结属性objects和maps没有objects或可能这是一个错误/尚未实现?

是的,我知道,我应该使用Immutable.js,但有没有办法用本机ES6地图做到这一点?

log*_*yth 9

没有,你可以写一个包装来做到这一点.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();
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您需要在ES5环境中工作,您可以轻松地为一个包装类Map而不是扩展Map该类.

  • ...但当然这不会阻止任何人做`Map.prototype.clear.call(thinklyFrozenMap) (3认同)
  • @Bergi True,我假设目标是避免意外突变,而不是真正的冻结。你需要为此做包装类。 (2认同)
  • 虽然我喜欢静默返回的想法,但最好模仿原始的返回类型,因此对于set(),`this`表示删除()的`false`(?)和清除的`undefined`. (2认同)

Tie*_*eme 6

@loganfsmyth,你的回答给了我一个想法,这是怎么回事:

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);
}
Run Code Online (Sandbox Code Playgroud)

这对我来说很完美:)


在评论中更新了@Bergi中的点数:

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);
}
Run Code Online (Sandbox Code Playgroud)

  • 你不能通过`Map.prototype.set.call(myMap, 'key', 'value')`来解决这个问题吗?我测试过,你可以通过这种方式通过冻结功能。要实际创建冻结视图,您需要返回一个对象包装器,该包装器仅通过捕获引用底层映射并仅提供读取方法。 (2认同)