2016-03-02 10 views
8

Sto cercando un modo per bloccare le mappe ES6 native.C'è un modo per bloccare una mappa ES6?

Object.freeze e Object.seal non sembrano funzionare:

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

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

myMap.set("key2", "value2"); 
// Map { 'key1' => 'value1', 'key2' => 'value2' } 

È questo il comportamento destinato dal congelamento congela proprietà di objects e maps non sono objects o potrebbe essere questo un bug/non ancora implementato?

E sì, lo so, probabilmente dovrei usare Immutable.js, ma c'è un modo per farlo con le mappe ES6 native?

+0

correlati: [C'è un modo per Object.freeze() una data JavaScript?] (Http://stackoverflow.com/q/34907311/1048572) – Bergi

+0

(Prima ho pensato che la tua domanda fosse un duplicato, ma non ho trovato nessuno finché non ho cercato il problema senza 'Map') – Bergi

risposta

4

@loganfsmyth, la tua risposta mi ha dato un'idea, che dire di questo:

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); 
} 

Questo funziona perfettamente per me :)


Aggiornato con punti da @Bergi nei commenti:

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); 
} 
+0

Sembra buono, anche se ometterei il controllo 'instanceof' come lo chiamavate' freezeMap' già. E potresti mettere in cache i metodi (per minuscoli miglioramenti dello spazio di memoria) all'esterno, invece di ricrearli per ogni chiamata. E naturalmente ha ancora lo stesso "difetto" della soluzione di logan, non impedendo 'Map.prototype.clear.call (myMap)'. Nessuno di questi ha davvero importanza, ma hai chiesto i miei pensieri :-) – Bergi

+0

Punti giusti! Sempre alla ricerca di miglioramenti, quindi grazie :). E sì, quel "difetto" è ancora lì, ma per me non importa molto visto che lo userò solo per i test. – Tieme

+0

'mapClear' non dovrebbe avere alcun parametro. – Smartkid

5

Non c'è, è possibile scrivere un wrapper per farlo. Object.freeze blocca le proprietà di un oggetto, ma mentre le istanze Map sono oggetti, i valori che memorizzano non sono proprietà, quindi il congelamento non ha alcun effetto su di essi, proprio come qualsiasi altra classe che ha uno stato interno nascosto.

In un vero e proprio ambiente di ES6 in cui i comandi incorporati che si estendono è supportato (non Babel), si potrebbe fare questo:

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(); 
    } 
} 

Se avete bisogno di lavorare in ambienti ES5, si potrebbe facilmente fare una classe wrapper per a Map anziché estendere la classe Map.

+2

... ma ovviamente questo non impedirà a nessuno di fare' Map.prototype .clear.call (presumibilmenteFrozenMap) ' – Bergi

+1

@Bergi Vero, stavo assumendo che l'obiettivo era quello di evitare la mutazione accidentale, non il vero congelamento. Dovresti fare la classe wrapper per quello. – loganfsmyth

+0

L'obiettivo era infatti evitare la mutazione accidentale durante i test. Ma in effetti usando babel ... prenderò un altro sguardo per vedere se posso migrare l'intero codice di base a immutabile. Grazie! – Tieme

Problemi correlati