2009-02-02 6 views
76

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

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 è una buona pratica. Ci sono altri, migliori modi per simulare una struttura in Javascript?

risposta

145

L'unica differenza tra i letterali degli oggetti 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 

si potrebbe fare una fabbrica di struct.

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 
+14

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

+0

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

24

Io uso sempre letterali oggetto

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

non che rendere molto più difficile da mantenere (si dovrebbe vuoi aggiungere un nuovo campo in futuro) e anche molto più codice (ridigitare "id", "speaker", "country" ogni volta)? – nickf

+4

È esattamente tanto quanto è possibile mantenere una soluzione con le classi perché a JavaScript non interessa il numero di argomenti con cui si chiama la funzione. La ridigitazione non è un problema se si utilizzano strumenti giusti come Emacs. E puoi vedere ciò che equivale a ciò che rende gli errori obsoleti come lo scambio di argomenti. – vava

+3

Ma il più grande pro è scrivere meno codice e sarà più pulito :) – vava

2

io uso gli oggetti JSON stile per le strutture muti (senza funzioni membro).

7

Credo che la creazione di una classe per simulare le strutture C-like, come hai fatto, è il modo migliore .

È un ottimo modo per raggruppare i dati correlati e semplifica il passaggio dei parametri alle funzioni. Direi anche che una classe JavaScript è più simile a una struct C++ che a una classe C++, considerando lo added effort necessario per simulare le reali caratteristiche orientate agli oggetti.

Ho scoperto che provare a rendere JavaScript più simile a un'altra lingua si complica rapidamente, ma sono pienamente in grado di utilizzare le classi JavaScript come strutture prive di funzionalità.

+0

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

9

Il vero problema è che le strutture in una lingua devono essere tipi di valore e tipi di riferimento. Le risposte proposte suggeriscono di utilizzare oggetti (che sono tipi di riferimento) al posto delle strutture. Anche se questo può servire al suo scopo, sottrae il punto che un programmatore vorrebbe realmente i benefici dell'uso 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.

1

seguito Markus di answer, nelle versioni più recenti di JS (ES6 credo) è possibile creare una fabbrica 'struct' più semplicemente utilizzando Arrow Functions e Rest Parameter 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 

si può far sembrare simile a 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 
0

ho fatto una piccola biblioteca per definire struct se si lavora con la compatibilità ES6.

Si tratta di un parser JKT si può checkout la repository del progetto qui JKT Parser

Per un esempio si può creare lo struct come questo

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