I'm looking for a way to freeze native ES6 Maps.
Object.freeze
and Object.seal
don't seem to work:
let myMap = new Map([["key1", "value1"]]); // Map { 'key1' => 'value1' } Object.freeze(myMap); Object.seal(myMap); myMap.set("key2", "value2"); // Map { 'key1' => 'value1', 'key2' => 'value2' }
Is this intended behavior since freeze freezes properties of objects
and maps
are no objects
or might this be a bug / not implemented yet?
And yes I know, I should probably use Immutable.js, but is there any way to do this with native ES6 Maps?
Object.freeze() Method freeze() which is used to freeze an object. Freezing an object does not allow new properties to be added to an object and prevents from removing or altering the existing properties. Object. freeze() preserves the enumerability, configurability, writability and the prototype of the object.
As an object, an array can be frozen; after doing so, its elements cannot be altered and no elements can be added to or removed from the array. freeze() returns the same object that was passed into the function. It does not create a frozen copy.
Mainly, the idea is to freeze the object itself and then recursively freeze each of its properties. We must ensure that we only freeze the object's own properties; we shouldn't mess with the prototype of the object! Note that, in the same way as Object. freeze() works, deepFreeze() also freezes the object in place.
There is not, you could write a wrapper to do that. Object.freeze
locks an object's properties, but while Map
instances are objects, the values they store are not properties, so freezing has no effect on them, just like any other class that has internal state hidden away.
In a real ES6 environment where extending builtins is supported (not Babel), you could do this:
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(); } }
If you need to work in ES5 environments, you could easily make a wrapper class for a Map
rather than extending the Map
class.
@loganfsmyth, your answer gave me an idea, what about this:
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); }
This works perfectly for me :)
Updated with points from @Bergi in the comments:
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); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With