Structs en Javascript


112

Auparavant, lorsque j'avais besoin de stocker un certain nombre de variables liées, je créais une 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')
];

Mais je me demande si c'est une bonne pratique. Existe-t-il d'autres moyens plus efficaces pour simuler une structure en Javascript?

Réponses:


184

La seule différence entre les littéraux d'objet et les objets construits réside dans les propriétés héritées du prototype.

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

Vous pouvez créer une fabrique de structures.

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
... puis j'ai compris les fonctions d'usine. +1 pour une réponse claire, compréhensible et concise, avec l'exemple d'usine.
John

J'aime cette approche, mais soyez prudent si vous utilisez le compilateur de fermeture. Le tuple n'est accessible que sous forme de chaîne dans ce cas, car les propriétés sont renommées. (Au moins en mode avancé)
kap

J'étais curieux de savoir l'efficacité de cette méthode sur les littéraux d'objet.
c0degeas

Il est peut-être également possible d'utiliser la classe JS.
SphynxTech le

31

J'utilise toujours des littéraux d'objet

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

2
cela ne rendrait-il pas beaucoup plus difficile à maintenir (devriez-vous vouloir ajouter un nouveau champ à l'avenir), et aussi beaucoup plus de code (retaper "id", "speaker", "country" à chaque fois)?
nickf le

5
C'est exactement aussi maintenable qu'une solution avec des classes car JavaScript ne se soucie pas du nombre d'arguments avec lesquels vous appelez la fonction. La retaper n'est pas un problème si vous utilisez les bons outils comme Emacs. Et vous pouvez voir ce qui équivaut à ce qui rend les erreurs comme l'échange d'arguments obsolètes.
vava le

4
Mais le plus grand avantage est que vous
écririez

1
La retaper @vava est toujours un problème, car il y a plus de sauts que de copier le nouvel archétype ___ (,,,). De plus, il n'y a pas de lisibilité. Une fois que vous vous êtes habitué au codage, il new READABLE_PART(ignore everything in here)devient très scannable et auto-documenté, par opposition à {read: "ignore", everything: "ignore", in: "ignore", here: "ignore"} // and then come up with READABLE_PARTdans votre tête. La première version est lisible en paginant rapidement. Le second, vous refactorisez en structures simplement pour comprendre.
Christopher

19

Le vrai problème est que les structures d'un langage sont supposées être des types valeur et non des types référence. Les réponses proposées suggèrent d'utiliser des objets (qui sont des types de référence) à la place des structures. Bien que cela puisse servir son objectif, cela évite le fait qu'un programmeur voudrait réellement les avantages de l'utilisation de types valeur (comme une primitive) au lieu d'un type référence. Les types valeur, pour un, ne devraient pas provoquer de fuites de mémoire.


8

Je pense que créer une classe pour simuler des structures de type C, comme vous l'avez fait, est le meilleur moyen.

C'est un excellent moyen de regrouper les données associées et de simplifier la transmission de paramètres aux fonctions. Je dirais également qu'une classe JavaScript ressemble plus à une structure C ++ qu'à une classe C ++, compte tenu de l' effort supplémentaire nécessaire pour simuler des fonctionnalités orientées objet réelles.

J'ai constaté qu'essayer de rendre JavaScript plus semblable à un autre langage se compliquait rapidement, mais je supporte pleinement l'utilisation des classes JavaScript comme structures sans fonction.


J'aimerais avoir quelque chose comme des structures, des tuples - quelque chose qui permet des collections de données fortement typées - qui est traité au moment de la compilation et qui n'a pas la surcharge des hashmaps comme des objets
derekdreery

4

Suite à la réponse de Markus , dans les nouvelles versions de JS (ES6 je pense), vous pouvez créer une usine `` struct '' plus simplement en utilisant les fonctions de flèche et le paramètre de repos comme ceci:

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

Le résultat de l'exécution de ceci est:

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

Vous pouvez le faire ressembler au namedtuple 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);

Et les résultats:

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

Cela ressemble à la structure en C / C ++ et dans d'autres langages, mais en réalité ce n'est pas le cas - les propriétés des objets ne sont pas garanties d'être ordonnées comme suit: Définition d'un objet d'ECMAScript Third Edition (pdf): 4.3.3 Objet Un objet est un membre du type Object. Il s'agit d'une collection non ordonnée de propriétés dont chacune contient une valeur primitive, un objet ou une fonction. Une fonction stockée dans une propriété d'un objet est appelée une méthode
tibetty

3

J'utilise des objets de style JSON pour les structures stupides (pas de fonctions membres).


1

J'ai créé une petite bibliothèque pour définir struct si vous travaillez avec la compatibilité ES6.

C'est un analyseur JKT, vous pouvez extraire le référentiel du projet ici Analyseur JKT

Pour un exemple, vous pouvez créer votre structure comme ceci

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

C'est plus de travail à mettre en place, mais si la maintenabilité bat un effort ponctuel, cela peut être votre cas.

/**
 * @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;
    }
}

Avantages:

  • non lié à l'ordre des arguments
  • facilement extensible
  • prise en charge des scripts de type:

entrez la description de l'image ici

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.