Strutture in Javascript


112

In precedenza, quando avevo bisogno di memorizzare un numero di variabili correlate, creavo una classe.

function Item(id, speaker, country) {
    this.id = id;
    this.speaker = spkr;
    this.country = country;
}
var myItems = [
    new Item(1, 'john', 'au'),
    new Item(2, 'mary', 'us')
];

Ma mi chiedo se questa sia una buona pratica. Esistono altri modi migliori per simulare una struttura in Javascript?

Risposte:


184

L'unica differenza tra i letterali oggetto e gli oggetti costruiti sono le proprietà ereditate dal prototipo.

var o = {
  'a': 3, 'b': 4,
  'doStuff': function() {
    alert(this.a + this.b);
  }
};
o.doStuff(); // displays: 7

Potresti fare una fabbrica di strutture.

function makeStruct(names) {
  var names = names.split(' ');
  var count = names.length;
  function constructor() {
    for (var i = 0; i < count; i++) {
      this[names[i]] = arguments[i];
    }
  }
  return constructor;
}

var Item = makeStruct("id speaker country");
var row = new Item(1, 'john', 'au');
alert(row.speaker); // displays: john

27
... e poi ho capito le funzioni di fabbrica. +1 per una risposta chiara, comprensibile e concisa, insieme all'esempio di fabbrica.
Giovanni

Mi piace questo approccio, tuttavia fai attenzione se usi il compilatore di chiusura. In questo caso è possibile accedere alla tupla solo come stringa, poiché le proprietà vengono rinominate. (Almeno in modalità avanzata)
kap

Ero curioso dell'efficienza di questo metodo rispetto ai letterali oggetto.
c0degeas

Forse è anche possibile utilizzare la classe JS.
SphynxTech

31

Uso sempre oggetti letterali

{id: 1, speaker:"john", country: "au"}

2
non sarebbe molto più difficile da mantenere (dovresti voler aggiungere un nuovo campo in futuro), e anche molto più codice (ridigitando "id", "speaker", "country" ogni volta)?
nickf

5
È esattamente gestibile come la soluzione con le classi perché JavaScript non si preoccupa del numero di argomenti con cui chiami la funzione. La riscrittura non è un problema se usi strumenti giusti come Emacs. E puoi vedere cosa è uguale a ciò che rende obsoleti errori come lo scambio di argomenti.
vava

4
Ma il più grande vantaggio è che scriveresti meno codice e sarà più pulito :)
vava

1
La riscrittura di @vava è ancora un problema, poiché ci sono più salti che copiare il nuovo archetipo ___ (,,,). Inoltre, non c'è leggibilità. Una volta che ti sei abituato alla codifica, new READABLE_PART(ignore everything in here)diventa molto scansionabile e auto-documentante, al contrario {read: "ignore", everything: "ignore", in: "ignore", here: "ignore"} // and then come up with READABLE_PARTdella tua testa. La prima versione è leggibile mentre si sfoglia rapidamente. Il secondo, esegui il refactoring in strutture semplicemente per comprendere.
Christopher

19

Il vero problema è che le strutture in un linguaggio dovrebbero essere tipi di valore e non tipi di riferimento. Le risposte proposte suggeriscono di utilizzare oggetti (che sono tipi di riferimento) al posto delle strutture. Sebbene ciò possa servire allo scopo, elude il punto che un programmatore vorrebbe effettivamente i vantaggi dell'utilizzo di tipi di valore (come una primitiva) al posto del tipo di riferimento. I tipi di valore, per esempio, non dovrebbero causare perdite di memoria.


8

Penso che creare una classe per simulare strutture tipo C, come hai fatto tu, sia il modo migliore .

È un ottimo modo per raggruppare i dati correlati e semplifica il passaggio di parametri alle funzioni. Direi anche che una classe JavaScript è più simile a una struttura C ++ che a una classe C ++, considerando lo sforzo aggiuntivo necessario per simulare funzionalità orientate agli oggetti reali.

Ho scoperto che provare a rendere JavaScript più simile a un altro linguaggio diventa complicato velocemente, ma supporto completamente l'utilizzo di classi JavaScript come strutture senza funzioni.


Mi piacerebbe avere qualcosa come struct, tuple - qualcosa che consente raccolte di dati fortemente tipizzate - che viene gestito in fase di compilazione e non ha il sovraccarico di hashmap come oggetti
derekdreery

4

Seguendo la risposta di Markus , nelle versioni più recenti di JS (ES6 credo) puoi creare una fabbrica 'struct' più semplicemente usando le funzioni freccia e il parametro di riposo in questo modo:

const Struct = (...keys) => ((...v) => keys.reduce((o, k, i) => {o[k] = v[i]; return o} , {}))
const Item = Struct('id', 'speaker', 'country')
var myItems = [
    Item(1, 'john', 'au'),
    Item(2, 'mary', 'us')
];

console.log(myItems);
console.log(myItems[0].id);
console.log(myItems[0].speaker);
console.log(myItems[0].country);

Il risultato dell'esecuzione di questo è:

[ { id: 1, speaker: 'john', country: 'au' },
  { id: 2, speaker: 'mary', country: 'us' } ]
1
john
au

Puoi farlo sembrare simile alla namedtuple di Python:

const NamedStruct = (name, ...keys) => ((...v) => keys.reduce((o, k, i) => {o[k] = v[i]; return o} , {_name: name}))
const Item = NamedStruct('Item', 'id', 'speaker', 'country')
var myItems = [
    Item(1, 'john', 'au'),
    Item(2, 'mary', 'us')
];

console.log(myItems);
console.log(myItems[0].id);
console.log(myItems[0].speaker);
console.log(myItems[0].country);

E i risultati:

[ { _name: 'Item', id: 1, speaker: 'john', country: 'au' },
  { _name: 'Item', id: 2, speaker: 'mary', country: 'us' } ]
1
john
au

Sembra la struttura in C / C ++ e in altri linguaggi, ma in realtà non lo è: non è garantito che le proprietà negli oggetti siano ordinate come segue: Definizione di un oggetto da ECMAScript Terza edizione (pdf): 4.3.3 Oggetto Un oggetto è un membro del tipo Object. È una raccolta non ordinata di proprietà, ciascuna delle quali contiene un valore, un oggetto o una funzione primitiva. Una funzione memorizzata in una proprietà di un oggetto è chiamata metodo
tibetty

3

Uso gli oggetti in stile JSON per strutture stupide (nessuna funzione membro).


1

Ho creato una piccola libreria per definire la struttura se lavori con la compatibilità ES6.

È un parser JKT, puoi controllare il repository del progetto qui JKT Parser

Per un esempio puoi creare la tua struttura in questo modo

const Person = jkt`
    name: String
    age: Number
`

const someVar = Person({ name: "Aditya", age: "26" })

someVar.name // print "Aditya"
someVar.age // print 26 (integer)

someVar.toJSON() // produce json object with defined schema 

0

È più lavoro da configurare, ma se la manutenibilità batte lo sforzo una tantum, questo potrebbe essere il tuo caso.

/**
 * @class
 */
class Reference {

    /**
     * @constructs Reference
     * @param {Object} p The properties.
     * @param {String} p.class The class name.
     * @param {String} p.field The field name.
     */
    constructor(p={}) {
        this.class = p.class;
        this.field = p.field;
    }
}

vantaggi:

  • non vincolato all'ordine degli argomenti
  • facilmente allungabile
  • digita supporto script:

inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.