Strukturen in Javascript


112

Wenn ich zuvor eine Reihe verwandter Variablen speichern musste, habe ich eine Klasse erstellt.

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

Aber ich frage mich, ob dies eine gute Praxis ist. Gibt es andere, bessere Möglichkeiten, eine Struktur in Javascript zu simulieren?

Antworten:


184

Der einzige Unterschied zwischen Objektliteralen und konstruierten Objekten sind die vom Prototyp geerbten Eigenschaften.

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

Sie könnten eine Strukturfabrik erstellen.

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
... und dann habe ich die Fabrikfunktionen verstanden. +1 für eine klare, verständliche und präzise Antwort zusammen mit dem Fabrikbeispiel.
John

Ich mag diesen Ansatz, aber seien Sie vorsichtig, wenn Sie den Closure-Compiler verwenden. Auf das Tupel kann in diesem Fall nur als Zeichenfolge zugegriffen werden, da die Eigenschaften umbenannt werden. (Zumindest im fortgeschrittenen Modus)
Kap

Ich war neugierig auf die Effizienz dieser Methode gegenüber den Objektliteralen.
c0degeas

Es ist möglicherweise auch möglich, die JS-Klasse zu verwenden.
SphynxTech

31

Ich benutze immer Objektliterale

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

2
Wäre das nicht viel schwieriger zu pflegen (sollten Sie in Zukunft ein neues Feld hinzufügen wollen) und auch viel mehr Code (jedes Mal "id", "Sprecher", "Land" erneut eingeben)?
Nickf

5
Es ist genauso wartbar wie eine Lösung mit Klassen, da JavaScript die Anzahl der Argumente, mit denen Sie die Funktion aufrufen, nicht berücksichtigt. Das erneute Eingeben ist kein Problem, wenn Sie die richtigen Tools wie Emacs verwenden. Und Sie können sehen, was gleich ist, was Fehler wie das Austauschen von Argumenten überflüssig macht.
Vava

4
Aber der größte
Vorteil

1
@vava Retyping ist immer noch ein Problem, da es mehr Sprünge gibt als das Kopieren des neuen ___ (,,,) Archetyps. Es gibt auch keine Lesbarkeit. Sobald Sie sich an das Codieren new READABLE_PART(ignore everything in here)gewöhnt haben , wird es sehr scannbar und selbstdokumentierend, im Gegensatz zu {read: "ignore", everything: "ignore", in: "ignore", here: "ignore"} // and then come up with READABLE_PARTin Ihrem Kopf. Die erste Version ist lesbar, während Sie schnell blättern. Die zweite, Sie Refactor in Strukturen nur zu verstehen.
Christopher

19

Das eigentliche Problem ist, dass Strukturen in einer Sprache Werttypen und keine Referenztypen sein sollen. In den vorgeschlagenen Antworten wird vorgeschlagen, anstelle von Strukturen Objekte (Referenztypen) zu verwenden. Dies kann zwar seinen Zweck erfüllen, umgeht jedoch den Punkt, an dem ein Programmierer tatsächlich die Vorteile der Verwendung von Werttypen (wie ein Grundelement) anstelle des Referenztyps haben möchte. Zum einen sollten Werttypen keine Speicherlecks verursachen.


8

Ich denke, eine Klasse zu erstellen, um C-ähnliche Strukturen zu simulieren, wie Sie es getan haben, ist das Beste Weg.

Dies ist eine großartige Möglichkeit, verwandte Daten zu gruppieren und die Übergabe von Parametern an Funktionen zu vereinfachen. Ich würde auch argumentieren, dass eine JavaScript-Klasse eher einer C ++ - Struktur als einer C ++ - Klasse ähnelt, wenn man bedenkt, wie viel Aufwand erforderlich ist, um echte objektorientierte Features zu simulieren.

Ich habe festgestellt, dass der Versuch, JavaScript einer anderen Sprache ähnlicher zu machen, schnell kompliziert wird, aber ich unterstütze die Verwendung von JavaScript-Klassen als funktionslose Strukturen voll und ganz.


Ich würde gerne so etwas wie Strukturen, Tupel haben - etwas, das stark typisierte Datensammlungen ermöglicht - das zur Kompilierungszeit behandelt wird und nicht den Overhead von Hashmaps wie Objekten hat
derekdreery

4

Nach Markus ' Antwort können Sie in neueren Versionen von JS (ES6, glaube ich) eine' struct'-Factory einfacher erstellen, indem Sie die Pfeilfunktionen und den Rest-Parameter wie folgt verwenden:

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

Das Ergebnis dieser Ausführung ist:

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

Sie können es ähnlich wie Pythons Namedtuple aussehen lassen:

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

Und die Ergebnisse:

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

Es sieht aus wie die Struktur in C / C ++ und anderen Sprachen, ist es aber nicht - die Eigenschaften in Objekten können nicht wie folgt geordnet werden: Definition eines Objekts aus ECMAScript Third Edition (pdf): 4.3.3 Objekt Ein Objekt ist ein Mitglied vom Typ Objekt. Es ist eine ungeordnete Sammlung von Eigenschaften, von denen jede einen primitiven Wert, ein Objekt oder eine Funktion enthält. Eine in einer Eigenschaft eines Objekts gespeicherte Funktion wird als Methode bezeichnet
tibetty

3

Ich verwende Objekte im JSON-Stil für dumme Strukturen (keine Mitgliedsfunktionen).


1

Ich habe eine kleine Bibliothek erstellt, um struct zu definieren, wenn Sie mit ES6-Kompatibilität arbeiten.

Es ist ein JKT-Parser, den Sie hier im Projekt-Repository auschecken können auschecken können. JKT-Parser

Zum Beispiel können Sie Ihre Struktur so erstellen

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

Das Einrichten ist mehr Arbeit, aber wenn die Wartbarkeit die einmalige Anstrengung übertrifft, kann dies Ihr Fall sein.

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

Vorteile:

  • nicht an die Argumentreihenfolge gebunden
  • leicht ausziehbar
  • Unterstützung für Typenskripte:

Geben Sie hier die Bildbeschreibung ein

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.