Structs em Javascript


112

Anteriormente, quando eu precisava armazenar várias variáveis ​​relacionadas, eu criava uma 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')
];

Mas estou me perguntando se essa é uma boa prática. Existe alguma outra maneira melhor de simular uma estrutura em Javascript?

Respostas:


184

A única diferença entre literais de objeto e objetos construídos são as propriedades herdadas do protótipo.

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

Você poderia fazer uma fábrica de estruturas.

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 então eu entendi as funções da fábrica. +1 para uma resposta clara, compreensível e concisa, juntamente com o exemplo de fábrica.
João,

Eu gosto dessa abordagem, no entanto, tome cuidado se você usar o compilador de encerramento. A tupla só pode ser acessada como string neste caso, porque as propriedades são renomeadas. (Pelo menos no modo avançado)
kap

Eu estava curioso sobre a eficiência desse método em relação aos literais de objeto.
c0degeas

Talvez também seja possível usar a classe JS.
SphynxTech

31

Eu sempre uso literais de objeto

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

2
isso não tornaria muito mais difícil de manter (se você quiser adicionar um novo campo no futuro), e também muito mais código (redigitar "id", "alto-falante", "país" todas as vezes)?
nickf

5
É exatamente tão sustentável quanto uma solução com classes porque o JavaScript não se preocupa com o número de argumentos com os quais você chama a função. A redigitação não é um problema se você usar as ferramentas certas como o Emacs. E você pode ver o que é igual ao que torna obsoletos erros como a troca de argumentos.
vava

4
Mas a maior vantagem é que você escreveria menos código e seria mais limpo :)
vava

1
A redigitação do @vava ainda é um problema, pois há mais saltos do que copiar o novo arquétipo ___ (,,,). Além disso, não há legibilidade. Depois que você se acostuma com a codificação, new READABLE_PART(ignore everything in here)torna-se muito digitalizável e autodocumentável, ao contrário de {read: "ignore", everything: "ignore", in: "ignore", here: "ignore"} // and then come up with READABLE_PARTsua cabeça. A primeira versão pode ser lida durante o paging rapidamente. A segunda, você refatora em estruturas apenas para entender.
Christopher

19

O verdadeiro problema é que as estruturas em uma linguagem devem ser tipos de valor e não tipos de referência. As respostas propostas sugerem o uso de objetos (que são tipos de referência) no lugar de estruturas. Embora isso possa servir ao seu propósito, ele contorna o ponto de que um programador realmente desejaria os benefícios de usar tipos de valor (como um primitivo) em vez do tipo de referência. Os tipos de valor, por exemplo, não devem causar vazamentos de memória.


8

Acho que criar uma classe para simular estruturas semelhantes a C, como você tem feito, é a melhor maneira.

É uma ótima maneira de agrupar dados relacionados e simplifica a passagem de parâmetros para funções. Eu também diria que uma classe JavaScript é mais parecida com uma estrutura C ++ do que com uma classe C ++, considerando o esforço adicional necessário para simular recursos reais orientados a objetos.

Descobri que tentar tornar o JavaScript mais parecido com outra linguagem fica complicado rápido, mas eu apoio totalmente o uso de classes JavaScript como estruturas sem função.


Eu adoraria ter algo como structs, tuplas - algo que permite coleções de dados fortemente tipados - que é tratado em tempo de compilação e não tem a sobrecarga de hashmaps como objetos
derekdreery

4

Seguindo a resposta de Markus , em versões mais recentes de JS (ES6 eu acho), você pode criar uma fábrica de 'estrutura' de forma mais simples usando Funções de seta e Parâmetro de descanso como:

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

O resultado disso é:

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

Você pode torná-lo semelhante ao namedtuple do 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 os resultados:

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

Parece a estrutura em C / C ++ e outras linguagens, mas na verdade não é - as propriedades em objetos não têm garantia de serem ordenadas descritas a seguir: Definição de um Objeto de ECMAScript Terceira Edição (pdf): 4.3.3 Objeto Um objeto é membro do tipo Object. É uma coleção não ordenada de propriedades, cada uma das quais contendo um valor, objeto ou função primitiva. Uma função armazenada em uma propriedade de um objeto é chamada de método
tibetty

3

Eu uso objetos de estilo JSON para estruturas burras (sem funções de membro).


1

Fiz uma pequena biblioteca para definir struct se você trabalha com compatibilidade ES6.

É um analisador JKT, você pode verificar o repositório do projeto aqui. JKT Parser

Por exemplo, você pode criar sua estrutura como esta

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

É mais trabalhoso configurar, mas se a manutenção supera o esforço único, então este pode ser o seu 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;
    }
}

Vantagens:

  • não vinculado à ordem do argumento
  • facilmente extensível
  • digite suporte de script:

insira a descrição da imagem aqui

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.