Estructuras en Javascript

112

Anteriormente, cuando necesitaba almacenar una serie de variables relacionadas, creaba una clase.

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')
];

Pero me pregunto si esta es una buena práctica. ¿Existen otras formas mejores de simular una estructura en Javascript?

nickf
fuente

Respuestas:

184

La única diferencia entre los objetos literales y los objetos construidos son las propiedades heredadas del prototipo.

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

Podrías hacer una fábrica de estructuras.

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
Markus Jarderot
fuente
27
... y luego entendí las funciones de fábrica. +1 para obtener una respuesta clara, comprensible y concisa, junto con el ejemplo de fábrica.
John
Me gusta este enfoque, sin embargo, tenga cuidado si usa el compilador de cierre. En este caso, solo se puede acceder a la tupla como cadena, porque se cambia el nombre de las propiedades. (Al menos en modo avanzado)
kap
Tenía curiosidad por la eficacia de este método sobre los objetos literales.
c0degeas
Quizás también sea posible utilizar la clase JS.
SphynxTech
31

Siempre uso literales de objeto

{id: 1, speaker:"john", country: "au"}
vava
fuente
2
¿No haría eso mucho más difícil de mantener (si desea agregar un nuevo campo en el futuro), y también mucho más código (volviendo a escribir "id", "altavoz", "país" cada vez)?
nickf
5
Es exactamente tan fácil de mantener como una solución con clases porque a JavaScript no le importa la cantidad de argumentos con los que llama a la función. Volver a escribir no es un problema si utiliza las herramientas adecuadas como Emacs. Y puede ver lo que es igual a lo que hace que errores como el intercambio de argumentos sean obsoletos.
vava
4
Pero la mayor ventaja es que escribirías menos código y será más limpio :)
vava
1
La reescritura de @vava sigue siendo un problema, ya que hay más saltos que copiar el nuevo arquetipo ___ (,,,). Además, no hay legibilidad. Una vez que te acostumbras a la codificación, se new READABLE_PART(ignore everything in here)vuelve muy escaneable y autodocumentado, en lugar de hacerlo {read: "ignore", everything: "ignore", in: "ignore", here: "ignore"} // and then come up with READABLE_PARTen tu cabeza. La primera versión se puede leer mientras se avanza rápidamente. El segundo, refactoriza en estructuras simplemente para entender.
Christopher
19

El problema real es que se supone que las estructuras en un lenguaje son tipos de valor, no tipos de referencia. Las respuestas propuestas sugieren el uso de objetos (que son tipos de referencia) en lugar de estructuras. Si bien esto puede cumplir su propósito, evita el punto de que un programador realmente querría los beneficios de usar tipos de valor (como un primitivo) en lugar del tipo de referencia. Los tipos de valor, por ejemplo, no deberían causar pérdidas de memoria.

Mario
fuente
8

Creo que crear una clase para simular estructuras similares a C, como lo has estado haciendo, es la mejor manera.

Es una excelente manera de agrupar datos relacionados y simplifica el paso de parámetros a funciones. También diría que una clase de JavaScript se parece más a una estructura de C ++ que a una clase de C ++, considerando el esfuerzo adicional necesario para simular características orientadas a objetos reales.

Descubrí que tratar de hacer que JavaScript se parezca más a otro lenguaje se vuelve complicado rápidamente, pero soy totalmente compatible con el uso de clases de JavaScript como estructuras sin funciones.

pedro
fuente
Me encantaría tener algo como estructuras, tuplas, algo que permita colecciones de datos fuertemente tipadas, que se maneje en tiempo de compilación y no tenga la sobrecarga de hashmaps como objetos
derekdreery
4

Siguiendo la respuesta de Markus , en las versiones más nuevas de JS (ES6, creo), puede crear una fábrica de 'estructuras' de manera más simple usando las funciones de flecha y el parámetro de descanso de esta manera:

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

El resultado de ejecutar esto es:

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

Puede hacer que se vea similar a la tupla con nombre de 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);

Y los resultados:

[ { _name: 'Item', id: 1, speaker: 'john', country: 'au' },
  { _name: 'Item', id: 2, speaker: 'mary', country: 'us' } ]
1
john
au
typoerrpr
fuente
Se parece a la estructura en C / C ++ y otros lenguajes, pero en realidad no lo es; no se garantiza que las propiedades de los objetos se ordenen como se describe a continuación: Definición de un objeto de ECMAScript Tercera edición (pdf): 4.3.3 Objeto Un objeto es miembro del tipo Object. Es una colección desordenada de propiedades, cada una de las cuales contiene un valor primitivo, objeto o función. Una función almacenada en una propiedad de un objeto se llama método
tibetty
3

Utilizo objetos estilo JSON para estructuras tontas (sin funciones miembro).

Robert Gould
fuente
1

Hice una pequeña biblioteca para definir la estructura si trabaja con compatibilidad con ES6.

Es un analizador JKT, puede consultar el repositorio del proyecto aquí JKT Parser

Por ejemplo, puede crear su estructura así

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 
Aditya Kresna Permana
fuente
0

Es más trabajo de configurar, pero si la capacidad de mantenimiento supera el esfuerzo de una sola vez, este puede ser su 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;
    }
}

Ventajas:

  • no vinculado al orden de los argumentos
  • fácilmente ampliable
  • soporte de escritura de tipo:

ingrese la descripción de la imagen aquí

Manuel
fuente