918 Stimmen

Selbstreferenzen in Objektliteralen/Initialisierern

Gibt es eine Möglichkeit, so etwas wie das Folgende in JavaScript zum Laufen zu bringen?

var foo = {
    a: 5,
    b: 6,
    c: this.a + this.b  // Doesn't work
};

In der aktuellen Form führt dieser Code offensichtlich zu einem Referenzfehler, da this bezieht sich nicht auf foo . Aber ist Gibt es eine Möglichkeit, die Werte in den Eigenschaften eines Objektliterales von anderen, früher deklarierten Eigenschaften abhängig zu machen?

3voto

DanielST Punkte 13135

Die anderen hier geposteten Antworten sind besser, aber hier ist eine Alternative, die:

  • Legt den Wert bei der Initialisierung fest (kein Getter, oder abgeleitet, etc.)
  • Benötigt keine Art von init() oder Code außerhalb des Objektliterales
  • ist ein Objektliteral und keine Fabrikfunktion oder ein anderer Mechanismus zur Objekterzeugung.
  • Sollte keine Auswirkungen auf die Leistung haben (außer bei der Initialisierung)

Selbstausführende anonyme Funktionen und Fensterspeicher

var foo = {
    bar:(function(){
        window.temp = "qwert";
        return window.temp;
    })(),
    baz: window.temp
};

Der Auftrag lautet garanti ( bar vor baz ).

Sie verschmutzt window natürlich, aber ich kann mir nicht vorstellen, dass jemand ein Skript schreibt, das eine window.temp hartnäckig zu sein. Vielleicht tempMyApp wenn Sie paranoid sind.

Sie ist auch hässlich, aber gelegentlich nützlich. Ein Beispiel ist, wenn Sie eine API mit starren Initialisierungsbedingungen verwenden und keine Lust haben, die Umstrukturierung vorzunehmen, damit das Scoping korrekt ist.

Und es ist natürlich trocken.

2voto

daviestar Punkte 4293

Wenn Ihr Objekt als Funktion geschrieben ist, die ein Objekt zurückgibt, UND Sie ES6 Objekt-Attribut "Methoden" verwenden, dann ist es möglich:

const module = (state) => ({
  a: 1,
  oneThing() {
    state.b = state.b + this.a
  },
  anotherThing() {
    this.oneThing();
    state.c = state.b + this.a
  },
});

const store = {b: 10};
const root = module(store);

root.oneThing();
console.log(store);

root.anotherThing();
console.log(store);

console.log(root, Object.keys(root), root.prototype);

2voto

UDrake Punkte 351

Hier ist eine nette ES6-Methode:

var foo = (o => ({
    ...o,
    c: o.a + o.b
  }))({
    a: 5,
    b: 6
  });

console.log(foo);

Ich verwende es etwa für folgende Zwecke:

const constants = Object.freeze(
  (_ => ({
    ..._,
    flag_data: {
      [_.a_flag]: 'foo',
      [_.b_flag]: 'bar',
      [_.c_flag]: 'oof'
    }
  }))({
    a_flag: 5,
    b_flag: 6,
    c_flag: 7,
  })
);

console.log(constants.flag_data[constants.b_flag]);

2voto

Der Schlüssel zu all dem ist SCOPE .

Sie müssen das "Elternteil" (übergeordnetes Objekt) der Eigenschaft, die Sie definieren möchten, als eigenes instanziiertes Objekt kapseln, und dann können Sie Verweise auf Geschwistereigenschaften mit dem Schlüsselwort this

Es ist sehr, sehr wichtig zu bedenken, dass, wenn Sie sich auf this ohne dies vorher zu tun, dann this bezieht sich auf den äußeren Bereich... das ist der window Objekt.

var x = 9   //this is really window.x
var bar = {
  x: 1,
  y: 2,
  foo: new function(){
    this.a = 5, //assign value
    this.b = 6,
    this.c = this.a + this.b;  // 11
  },
  z: this.x   // 9 (not 1 as you might expect, b/c *this* refers `window` object)
};

1voto

Snekse Punkte 14946

Ich werfe eine Option ein, da ich nicht gesehen habe, dass genau dieses Szenario behandelt wurde. Wenn Sie nicht wollen c aktualisiert, wenn a ou b aktualisieren, dann funktioniert ein ES6-IIFE gut.

var foo = ((a,b) => ({
    a,
    b,
    c: a + b
}))(a,b);

Für meine Bedürfnisse habe ich ein Objekt, das sich auf ein Array bezieht, das am Ende in einer Schleife verwendet wird, so dass ich nur einige gemeinsame Einrichtung einmal berechnen möchte, so ist dies, was ich habe:

let processingState = ((indexOfSelectedTier) => ({
    selectedTier,
    indexOfSelectedTier,
    hasUpperTierSelection: tiers.slice(0,indexOfSelectedTier)
                         .some(t => pendingSelectedFiltersState[t.name]),
}))(tiers.indexOf(selectedTier));

Da ich eine Eigenschaft festlegen muss für indexOfSelectedTier und ich muss diesen Wert verwenden, wenn ich die hasUpperTierSelection Eigenschaft, berechne ich diesen Wert zuerst und übergebe ihn als Parameter an das IIFE

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X