Ci è stato "permesso" di utilizzare metodi su mappe JavaScript (il tipo di dati) e in tal caso ci sono nuove regole?

7

Le mappe JavaScript (il tipo di dati, non il metodo dell'array) sembrano configurate per accettare dati (coppie chiave / valore) ma non necessariamente metodi. Almeno non sono pubblicizzati in questo modo. Tuttavia, possiamo mettere i metodi su un'istanza di mappa. Curiosamente, la parola chiave this funziona in tali metodi e restituisce la mappa stessa. Ad esempio:

const m = new Map();
m.set('key1', 'value1');
m.get('key1'); // returns 'value1', i.e. standard map usage
m.methodA = function(x) {console.log(x + ' to you too');};
m.methodA('hello'); // shows 'hello to you too'
m.methodB = function() {console.log(this.get('key1'));};
m.methodB(); // shows 'value1'

Questo è un uso corretto di mappe e / o metodi all'interno di mappe e / o this all'interno di metodi all'interno di mappe? O sto corrompendo qualcosa in qualche modo o infranto alcune regole facendo questo? Sembra abbastanza semplice e ragionevole, mi fa pensare che dovrebbe andare bene, ma non ho mai visto o sentito nulla prima che mi renda nervoso.

Non riesco a creare una mappa con un costruttore nel modo in cui posso creare un oggetto con un costruttore. Tuttavia, posso creare una fabbrica di mappe per produrre mappe di un determinato "tipo". Ad esempio, posso usare una fabbrica per creare mappe del "tipo di auto". Posso quindi anche allegare i metodi a ciascuna mappa di questo "tipo" includendoli in fabbrica:

const createCarMap = function(features) {
  const carMap = new Map(features);
  carMap.set('# tires', 'four (assumed)');
  carMap.speakersAreFeatured = function() {
    return this.has('speakers');
  };
  return carMap;
};
const yourCar = createCarMap([
  ['# cylinders', 'twelve'],
  ['speakers', 'awesome']
]);
const myCar = createCarMap([
  ['exterior', 'pearly white']
]);
yourCar.speakersAreFeatured(); // returns true
myCar.speakersAreFeatured();   // returns false

Tuttavia, tale metodo verrà applicato ripetutamente per ogni mappa prodotta. Ciò è in contrasto con il modo in cui i metodi possono essere aggiunti al prototipo di un oggetto, consentendo la riutilizzabilità del metodo. Quindi, i metodi possono essere collegati a una mappa in modo da consentire la riutilizzabilità del metodo?

La mia domanda più generale è: dovremmo usare metodi sulle mappe. Se é cosi, come? Dovremmo pensarci e usarli essenzialmente nello stesso modo in cui facciamo con gli oggetti, o ci sono "nuove regole" per utilizzarli con le mappe? (Suppongo che si possano fare domande simili anche su altri tipi di dati new-ish, ad esempio insiemi, weakMaps, ecc., Ma qui mi limiterò alle mappe.)

    
posta Andrew Willems 12.01.2017 - 02:22
fonte

3 risposte

2

Ispirato ai commenti di @Jules dopo la domanda originale, ho scoperto quanto segue: Se si utilizza ES6, è possibile creare una nuova classe che estenda il tipo di dati Mappa incorporato. Il costruttore dovrebbe passare tutti i parametri necessari a una chiamata super , creando la mappa e posizionandola in this . Quindi, qualsiasi codice all'interno della classe che deve utilizzare la mappa, nel costruttore o in uno qualsiasi dei suoi metodi, utilizza solo this .

class CarMap extends Map {
    constructor(features) {
        super(features);
        this.set('# tires', 'four (assumed)');
    }
    speakersAreFeatured() {
        return this.has('speakers');
    }
}

const yourCar = new CarMap([
  ['# cylinders', 'twelve'],
  ['speakers', 'awesome']
]);

const myCar = new CarMap([
  ['exterior', 'pearly white']
]);

console.log(yourCar.speakersAreFeatured()); // --> true
console.log(myCar.speakersAreFeatured());   // --> false
    
risposta data 13.01.2017 - 16:38
fonte
0

(Passaggio dal commento alla risposta)

Perché non estendi Map con:

Map.prototype.speakersAreFeatured = function() {
    return this.has('speakers');
};

Questo lo definirà per tutte le istanze di Map.

    
risposta data 12.01.2017 - 05:28
fonte
0

Aggiornamento: questa soluzione funziona e, per quanto posso dire, non infrange nessuna regola. Tuttavia, è una vecchia soluzione simile a ES5 al problema. Vedi la mia altra risposta per una soluzione più simile a ES6.

Suppongo che una soluzione sarebbe quella di seppellire la mappa all'interno di un oggetto normale come una delle proprietà di quell'oggetto (ad esempio mapObj ) e quindi associare i metodi a quell'oggetto piuttosto che alla mappa stessa. Quindi i metodi specifici della mappa si riferiscono alla mappa come una proprietà dell'oggetto genitore, cioè si riferiscono a this.mapObj piuttosto che semplicemente this . Questo sembra un po 'contorto / hacky in quanto l'unico scopo dell'oggetto genitore (istanziato dalla classe Car nell'esempio sotto) è di consentire il riutilizzo dei metodi da parte del codice, ma almeno lo fa.

(Giusto per chiarire una scelta di nome di variabile di seguito: Nell'esempio seguente chiamo la proprietà che contiene la mappa mapObj invece di solo map perché quest'ultima potrebbe confondere poiché esiste già uno standard map metodo su matrici che altrimenti potrebbero essere mescolate con.)

Nell'esempio seguente, la classe Car passa la features in una fabbrica di mappe interne. Quindi, nota la differenza tra le due varianti del corpo del metodo speakersAreFeatured :

  • come mostrato nella domanda: return this.has('speakers');

  • come mostrato nel codice seguente: return this.mapObj.has('speakers');

Codice:

class Car {
  constructor(features) {
    this.mapObj = this.createCarMap(features);
  }
  createCarMap(features) {
    const carMap = new Map(features);
    carMap.set('# tires', 'four (assumed)');
    return carMap;
  }
  speakersAreFeatured() {
    return this.mapObj.has('speakers');
  }
}

const yourCar = new Car([
  ['# cylinders', 'twelve'],
  ['speakers', 'awesome']
]);
const myCar = new Car([
  ['exterior', 'pearly white']
]);
yourCar.speakersAreFeatured(); // returns true
myCar.speakersAreFeatured();   // returns false
    
risposta data 13.01.2017 - 03:00
fonte

Leggi altre domande sui tag