Selbstreferenzen in Objektliteralen / Initialisierern


705

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 thislöst dieser Code offensichtlich einen Referenzfehler aus, da nicht darauf verwiesen wird foo. Aber gibt es eine Möglichkeit, Werte in den Eigenschaften eines Objektliterals von anderen zuvor deklarierten Eigenschaften abhängig zu machen?

Antworten:


744

Nun, das einzige, worüber ich Ihnen erzählen kann, ist Getter :

var foo = {
  a: 5,
  b: 6,
  get c() {
    return this.a + this.b;
  }
}

console.log(foo.c) // 11

Dies ist eine syntaktische Erweiterung, die durch die ECMAScript 5th Edition-Spezifikation eingeführt wurde. Die Syntax wird von den meisten modernen Browsern (einschließlich IE9) unterstützt.


32
Sehr hilfreiche Antwort. Weitere Informationen zu 'get' finden Sie hier: developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/…
jake

5
@FaustoR. Ja tut es.
Charlie Martin

48
Beachten Sie, dass sich bei dieser Lösung der Wert von auch synchron ändert, wenn die Werte von foo.aoder foo.bgeändert foo.cwerden. Dies kann erforderlich sein oder auch nicht.
HBP

8
Beachten Sie, dass thisan das tiefste verschachtelte Objekt gebunden wird. ZB:... x: { get c () { /*this is x, not foo*/ } } ...
Z. Khullah

3
Um meine obige Aussage zu vervollständigen, da foosie als Variable deklariert wird und cnur zum Zeitpunkt des Aufrufs ausgewertet wird, funktioniert die Verwendung von fooinside cim Gegensatz zu this(seien Sie jedoch vorsichtig)
Z. Khullah

316

Sie könnten so etwas tun wie:

var foo = {
   a: 5,
   b: 6,
   init: function() {
       this.c = this.a + this.b;
       return this;
   }
}.init();

Dies wäre eine Art einmalige Initialisierung des Objekts.

Beachten Sie, dass Sie die Zuordnung tatsächlich den Rückgabewert init()zu foo, also Sie haben return this.


95
Sie können auch delete this.initvorher, return thisdamit das foonicht verschmutzt ist
Billy Moon

15
@BillyMoon: Ja, obwohl dies die Leistung aller nachfolgenden Eigenschaftszugriffe auf dieses Objekt beeinflusst, auf viele Engines (z. B. V8).
TJ Crowder

8
@ MuhammadUmer: Ich bin mir nicht sicher, wie ES6-Klassen für die Frage relevant sind.
Felix Kling

8
@MuhammadUmer: Klassen sind nur syntaktischer Zucker für Konstruktorfunktionen, daher bieten sie nichts Neues. In beiden Fällen liegt der Schwerpunkt dieser Frage auf Objektliteralen.
Felix Kling

3
@akantoword: Großartig :) Da Objektliterale ein einzelner Ausdruck sind, wurde der init()Aufruf direkt an das Literal angehängt, um einen einzelnen Ausdruck beizubehalten . Aber natürlich können Sie die Funktion separat von Ihnen aufrufen.
Felix Kling

181

Die offensichtliche, einfache Antwort fehlt der Vollständigkeit halber:

Aber gibt es eine Möglichkeit, Werte in den Eigenschaften eines Objektliterals von anderen zuvor deklarierten Eigenschaften abhängig zu machen?

Nein. Alle Lösungen hier verschieben es bis nach dem Erstellen des Objekts (auf verschiedene Arten) und weisen dann die dritte Eigenschaft zu. Der einfachste Weg ist, dies einfach zu tun:

var foo = {
    a: 5,
    b: 6
};
foo.c = foo.a + foo.b;

Alle anderen sind nur indirektere Wege, um dasselbe zu tun. (Felix ist besonders clever, erfordert jedoch das Erstellen und Zerstören einer temporären Funktion, wodurch die Komplexität erhöht wird. Entweder verbleibt eine zusätzliche Eigenschaft für das Objekt oder [wenn Sie deletediese Eigenschaft haben] wirkt sich auf die Leistung nachfolgender Eigenschaftszugriffe auf dieses Objekt aus.)

Wenn alles in einem Ausdruck enthalten sein muss, können Sie dies ohne die temporäre Eigenschaft tun:

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

Oder natürlich, wenn Sie dies mehr als einmal tun müssen:

function buildFoo(a, b) {
    var o = {a: a, b: b};
    o.c = o.a + o.b;
    return o;
}

dann, wo Sie es verwenden müssen:

var foo = buildFoo(5, 6);

Aus Gründen meiner eigenen Gesundheit versuche ich, eine Art offizielle Dokumentation zu finden, die im Grunde dasselbe sagt - dass ein Objekt thisnur für Methoden dieses Objekts verfügbar ist und keine anderen Arten von Eigenschaften. Irgendeine Idee, wo ich das finden könnte? Vielen Dank!
David Kennell

1
@ DavidKennell: Wird nicht offizieller als die Spezifikation . :-) Du würdest wahrscheinlich hier anfangen und es durchziehen. Es ist eine ziemlich unangenehme Sprache, aber im Grunde werden Sie in den verschiedenen Unterabschnitten der Bewertung der Eigenschaftsdefinition sehen, dass das Objekt für die Operationen, die die Werte von Eigenschaftsinitialisierern bestimmen, nicht verfügbar ist.
TJ Crowder

Ich kann die Browser-Scope-Ergebnisse hier nicht sehen , aber das ist nicht mehr der Fall, oder? In meiner Umgebung ist v8: delete10% schneller und gecko: deletenur 1% langsamer.
TheMaster

1
@TheMaster - Ja, ich denke nicht, dass BrowserScope wirklich eine Sache mehr ist. Das Löschen scheint nicht mehr so ​​schlimm zu sein wie früher, zumindest nicht in V8 (Chrome usw.) oder SpiderMonkey. Immer noch langsamer, aber nur ein kleines bisschen, und diese Dinge sind heutzutage verdammt schnell.
TJ Crowder

63

Instanziieren Sie einfach eine anonyme Funktion:

var foo = new function () {
    this.a = 5;
    this.b = 6;
    this.c = this.a + this.b;
};

1
@Bergi, warum? Weil jemand ein anderes Objekt desselben Objekts daraus instanziieren könnte? Es ist nicht so, dass sie nicht einfach ein Objektliteral klonen können. Es ist nicht anders als das Übergeben eines Arguments, new Point(x, y)außer dass die Funktion nicht zur Wiederverwendung benannt ist.
zzzzBov

1
@zzzzBov: Natürlich können sie das Objekt nur klonen, aber im Vergleich zu einer IEFE-Lösung (wie in der Antwort von TJCrowder) verliert Ihre Lösung die Konstruktorfunktion und erstellt ein überflüssiges Prototypobjekt.
Bergi

5
@zzzzBov: Verwenden Sie einfach, var foo = function() { this.…; return this; }.call({});was syntaktisch nicht viel anders, aber semantisch vernünftig ist.
Bergi

1
@Bergi, wenn du denkst, dass es so wichtig ist, warum fügst du nicht deine eigene Antwort hinzu?
zzzzBov

3
Du hast das. Ich habe das newSchlüsselwort tatsächlich nicht bemerkt .
Randy

26

Jetzt können Sie in ES6 faul zwischengespeicherte Eigenschaften erstellen. Bei der ersten Verwendung wird die Eigenschaft einmal ausgewertet, um eine normale statische Eigenschaft zu werden. Ergebnis: Beim zweiten Mal wird der Overhead der mathematischen Funktion übersprungen.

Die Magie liegt im Getter.

const foo = {
    a: 5,
    b: 6,
    get c() {
        delete this.c;
        return this.c = this.a + this.b
    }
};

Im Pfeil thisnimmt Getter den umgebenden lexikalischen Bereich auf .

foo     // {a: 5, b: 6}
foo.c   // 11
foo     // {a: 5, b: 6 , c: 11}  

1
es5 verfügt auch über Eigenschaften, die Sie nur Object.defineProperty(foo, 'c', {get:function() {...}})zum Definieren verwenden müssen. Dies ist in einer Fabrik wie dieser leicht und unauffällig möglich. Wenn Sie den getZucker verwenden können, ist er natürlich besser lesbar, aber die Fähigkeit war vorhanden.
Aluan Haddad

21

Einige Schließungen sollten sich damit befassen;

var foo = function() {
    var a = 5;
    var b = 6;
    var c = a + b;

    return {
        a: a,
        b: b,
        c: c
    }
}();

Alle darin deklarierten Variablen foosind privat für foo, wie Sie es bei jeder Funktionsdeklaration erwarten würden, und da sie alle im Gültigkeitsbereich liegen, haben sie alle Zugriff aufeinander, ohne dass sie darauf verweisen müssen this, genau wie Sie es bei einer Funktion erwarten würden. Der Unterschied besteht darin, dass diese Funktion ein Objekt zurückgibt, das die privaten Variablen verfügbar macht und dieses Objekt zuweist foo. Am Ende geben Sie nur die Schnittstelle zurück, die Sie als Objekt mit der return {}Anweisung verfügbar machen möchten .

Die Funktion wird dann am Ende mit ausgeführt (), wodurch das gesamte foo-Objekt ausgewertet, alle Variablen innerhalb von instanziiert und das Rückgabeobjekt als Eigenschaften von hinzugefügt werden foo().


14
Es ist verwirrend und irreführend, dies als "Schließung" zu bezeichnen. Obwohl sich die Meinungen über die genaue Bedeutung der Rückgabe eines Objektwerts aus einer Funktion unterscheiden, ist dies in keinem Buch ein Abschluss.

16

Du könntest es so machen

var a, b
var foo = {
    a: a = 5,
    b: b = 6,
    c: a + b
}

Diese Methode hat sich für mich als nützlich erwiesen, als ich mich auf das Objekt beziehen musste, für das eine Funktion ursprünglich deklariert wurde. Das Folgende ist ein minimales Beispiel dafür, wie ich es verwendet habe:

function createMyObject() {
    var count = 0, self
    return {
        a: self = {
            log: function() {
                console.log(count++)
                return self
            }
        }
    }
}

Indem Sie self als das Objekt definieren, das die Druckfunktion enthält, erlauben Sie der Funktion, auf dieses Objekt zu verweisen. Dies bedeutet, dass Sie die Druckfunktion nicht an ein Objekt binden müssen, wenn Sie sie an eine andere Stelle übergeben müssen.

Wenn Sie stattdessen thiswie unten dargestellt verwenden würden

function createMyObject() {
    var count = 0
    return {
        a: {
            log: function() {
                console.log(count++)
                return this
            }
        }
    }
}

Dann protokolliert der folgende Code 0, 1, 2 und gibt dann einen Fehler aus

var o = createMyObject()
var log = o.a.log
o.a.log().log() // this refers to the o.a object so the chaining works
log().log() // this refers to the window object so the chaining fails!

Durch die Verwendung der self-Methode stellen Sie sicher, dass print unabhängig vom Kontext, in dem die Funktion ausgeführt wird, immer dasselbe Objekt zurückgibt. Der obige Code läuft einwandfrei und protokolliert 0, 1, 2 und 3, wenn Sie die Selbstversion von verwenden createMyObject().


3
Gute Beispiele, außer dass Sie alle Semikolons weggelassen haben.


9

Zum Abschluss haben wir in ES6 Klassen (die zum Zeitpunkt des Schreibens nur von den neuesten Browsern unterstützt wurden, aber in Babel, TypeScript und anderen Transpilern verfügbar sind).

class Foo {
  constructor(){
    this.a = 5;
    this.b = 6;
    this.c = this.a + this.b;
  }  
}

const foo = new Foo();

7

Sie können dies mithilfe des Modulmusters tun. So wie:

var foo = function() {
  var that = {};

  that.a = 7;
  that.b = 6;

  that.c = function() {
    return that.a + that.b;
  }

  return that;
};
var fooObject = foo();
fooObject.c(); //13

Mit diesem Muster können Sie je nach Bedarf mehrere foo-Objekte instanziieren.

http://jsfiddle.net/jPNxY/1/


2
Dies ist kein Beispiel für das Modulmuster, sondern nur eine Funktion. Wenn die letzte Zeile der foo-Definition }();wäre, würde sie sich selbst ausführen und ein Objekt zurückgeben, keine Funktion. Außerdem foo.cist eine Funktion, so schreibt es die Funktion und den nächsten Aufruf clobbers über fooObject.c()fehlschlagen. Vielleicht ist diese Geige näher an dem, was Sie wollen (es ist auch ein Singleton, der nicht zum Instanziieren gedacht ist).
Hollister

2
"Das Modulmuster wurde ursprünglich als eine Möglichkeit definiert, sowohl private als auch öffentliche Kapselung für Klassen in konventioneller Softwareentwicklung bereitzustellen." Von: Lernen von JavaScript-Entwurfsmustern . Das Objekt folgt dem oben beschriebenen Modulmuster, aber vielleicht ist es nicht das beste, um dies zu erklären, da keine öffentlichen und privaten Eigenschaften / Methoden angezeigt werden. Dieses Objekt jsfiddle.net/9nnR5/2 ist dasselbe Objekt mit öffentlichen und privaten Eigenschaften / Methoden. Also folgen beide diesem Muster
Rafael Rocha

6

Es gibt verschiedene Möglichkeiten, dies zu erreichen. das würde ich verwenden:

function Obj() {
 this.a = 5;
 this.b = this.a + 1;
 // return this; // commented out because this happens automatically
}

var o = new Obj();
o.b; // === 6

2
Dies funktioniert, beseitigt jedoch die Vorteile der Objektliteralnotation.
Kpozin

Es stimmt, tut mir leid, dass ich das Objekt-Literal-Tag ursprünglich verpasst habe. Ich verwende meistens nur Objektliterale für Datenstrukturen, und wann immer ich zusätzliche Logik möchte (die einer Klasse ähneln könnte), erstelle ich das Objekt aus genau diesem Grund als Ergebnis einer Funktion.
Ken

6

Nur zum Nachdenken - Platzieren Sie die Eigenschaften des Objekts außerhalb einer Zeitleiste:

var foo = {
    a: function(){return 5}(),
    b: function(){return 6}(),
    c: function(){return this.a + this.b}
}

console.log(foo.c())

Es gibt auch oben bessere Antworten . So habe ich den von Ihnen befragten Beispielcode geändert.

AKTUALISIEREN:

var foo = {
    get a(){return 5},
    get b(){return 6},
    get c(){return this.a + this.b}
}
// console.log(foo.c);

2
In ES6 können Sie diesen allgemeinen Ansatz viel eleganter gestalten: var foo = { get a(){return 5}, get b(){return 6}, get c(){return this.a + this.b} }Jetzt können Sie einfach foo.cstatt foo.c():) (Fühlen Sie sich frei, dies in Ihre Antwort

5

Das Erstellen einer neuen Funktion für Ihr Objektliteral und das Aufrufen eines Konstruktors scheint eine radikale Abkehr vom ursprünglichen Problem zu sein und ist unnötig.

Sie können während der Objektliteralinitialisierung nicht auf eine Geschwistereigenschaft verweisen.

var x = { a: 1, b: 2, c: a + b } // not defined 
var y = { a: 1, b: 2, c: y.a + y.b } // not defined 

Die einfachste Lösung für berechnete Eigenschaften folgt (kein Heap, keine Funktionen, kein Konstruktor):

var x = { a: 1, b: 2 };

x.c = x.a + x.b; // apply computed property

3

Die anderen hier veröffentlichten Antworten sind besser, aber hier ist eine Alternative:

  • Legt den Wert bei der Initialisierung fest (kein Getter oder abgeleitet usw.)
  • Benötigt keinen Typ init()oder Code außerhalb des Objektliteral
  • Ist ein Objektliteral und keine Fabrikfunktion oder eine andere Objekterstellungsmechanik.
  • 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
};

Die Bestellung ist garantiert ( barvorher baz).

Es verschmutzt windownatürlich, aber ich kann mir nicht vorstellen, dass jemand ein Skript schreibt window.temp, das hartnäckig sein muss. Vielleicht, tempMyAppwenn du paranoid bist.

Es ist auch hässlich, aber gelegentlich nützlich. Ein Beispiel ist, wenn Sie eine API mit starren Initialisierungsbedingungen verwenden und keine Lust auf Refactoring haben, damit der Umfang korrekt ist.

Und es ist natürlich trocken.


3

Der Schlüssel zu all dem ist SCOPE .

Sie müssen das "übergeordnete" (übergeordnete Objekt) der Eigenschaft, die Sie als eigenes instanziiertes Objekt definieren möchten, kapseln und dann mithilfe des Schlüsselworts Verweise auf Geschwistereigenschaften erstellen this

Es ist sehr, sehr wichtig , sich daran zu erinnern, dass, wenn Sie sich darauf beziehen, thisohne dies zuerst zu tun, thissich dies auf den äußeren Bereich bezieht ... der das windowObjekt sein wird.

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

2
Dies ist nicht einmal gültig JS.

2

Wenn Ihr Objekt als eine Funktion geschrieben ist, die ein Objekt zurückgibt, UND Sie ES6-Objektattribut-Methoden verwenden, ist Folgendes 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);

2

Ich verwende den folgenden Code als Alternative und es funktioniert. Und die Variable kann auch ein Array sein. (@ Fausto R.)

var foo = {
  a: 5,
  b: 6,
  c: function() {
    return this.a + this.b;
  },

  d: [10,20,30],
  e: function(x) {
    this.d.push(x);
    return this.d;
  }
};
foo.c(); // 11
foo.e(40); // foo.d = [10,20,30,40]

2

Hier ist eine nette ES6-Methode:

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

Ich benutze es, um so etwas zu tun:

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


1

Wie wäre es mit dieser Lösung? Dies funktioniert auch mit verschachtelten Objekten mit Array

      Object.prototype.assignOwnProVal
     = function (to,from){ 
            function compose(obj,string){ 
                var parts = string.split('.'); 
                var newObj = obj[parts[0]]; 
                if(parts[1]){ 
                    parts.splice(0,1);
                    var newString = parts.join('.'); 
                    return compose(newObj,newString); 
                } 
                return newObj; 
            } 
            this[to] = compose(this,from);
     } 
     var obj = { name : 'Gaurav', temp : 
                  {id : [10,20], city:
                        {street:'Brunswick'}} } 
     obj.assignOwnProVal('street','temp.city.street'); 
     obj.assignOwnProVal('myid','temp.id.1');

0

Eine Option einwerfen, da ich nicht genau dieses Szenario behandelt habe. Wenn Sie nicht wollen , cwenn aktualisiert aoder zu baktualisieren, dann arbeitet 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 letztendlich in einer Schleife verwendet wird. Daher möchte ich einige allgemeine Einstellungen nur einmal berechnen. Ich habe also Folgendes:

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

Da ich eine Eigenschaft für festlegen indexOfSelectedTierund diesen Wert beim Festlegen der hasUpperTierSelectionEigenschaft verwenden muss, berechne ich diesen Wert zuerst und übergebe ihn als Parameter an das IIFE


0

Ein anderer Ansatz wäre, das Objekt zuerst zu deklarieren, bevor ihm Eigenschaften zugewiesen werden:

const foo = {};
foo.a = 5;
foo.b = 6;
foo.c = foo.a + foo.b;  // Does work
foo.getSum = () => foo.a + foo.b + foo.c;  // foo.getSum() === 22

Damit können Sie den Objektvariablennamen verwenden, um auf die bereits zugewiesenen Werte zuzugreifen.
Am besten für config.jsDatei.


Dies ist keine Selbstreferenz, sondern eine Referenz auf die deklarierte Variable, foodie auf das betreffende Objekt verweist.
Derek Henderson

0
var x = {
    a: (window.secreta = 5),
    b: (window.secretb = 6),
    c: window.secreta + window.secretb
};

Dies ist fast identisch mit der Antwort von @ slicedtoad, verwendet jedoch keine Funktion.


-1

Hinweis: Diese Lösung verwendet Typescript (Sie können das Vanilla JS verwenden, mit dem TS bei Bedarf kompiliert wird).

class asd {
    def = new class {
        ads= 'asd';
        qwe= this.ads + '123';
    };

    // this method is just to check/test this solution 
    check(){
        console.log(this.def.qwe);
    }
}

// these two lines are just to check
let instance = new asd();
instance.check();

Hier wurden Klassenausdrücke verwendet, um die gewünschte verschachtelte Objektliteralschnittstelle zu erhalten. Dies ist meiner Meinung nach das nächstbeste, um die Eigenschaften eines Objekts während der Erstellung referenzieren zu können.

Beachten Sie vor allem, dass Sie bei Verwendung dieser Lösung genau dieselbe Schnittstelle haben wie bei einem Objektliteral. Und die Syntax kommt einem Objektliteral selbst ziemlich nahe (im Gegensatz zur Verwendung einer Funktion usw.).

Vergleichen Sie Folgendes

Lösung, die ich vorgeschlagen habe

class asd {
    def = new class {
        ads= 'asd';
        qwe= this.ads + '123';
    };

Lösung, wenn Objektliterale ausgereicht hätten

var asd = {
    def : {
        ads:'asd',
        qwe: this.ads + '123';, //ILLEGAL CODE; just to show ideal scenario
    }
}

Ein anderes Beispiel

Hier in dieser Klasse können Sie mehrere relative Pfade untereinander kombinieren, was mit einem Objektliteral nicht möglich ist.

class CONSTANT {
    static readonly PATH = new class {
        /** private visibility because these relative paths don't make sense for direct access, they're only useful to path class
         *
         */
        private readonly RELATIVE = new class {
            readonly AFTER_EFFECTS_TEMPLATE_BINARY_VERSION: fs.PathLike = '\\assets\\aep-template\\src\\video-template.aep';
            readonly AFTER_EFFECTS_TEMPLATE_XML_VERSION: fs.PathLike = '\\assets\\aep-template\\intermediates\\video-template.aepx';
            readonly RELATIVE_PATH_TO_AFTER_EFFECTS: fs.PathLike = '\\Adobe\\Adobe After Effects CC 2018\\Support Files\\AfterFX.exe';
            readonly OUTPUT_DIRECTORY_NAME: fs.PathLike = '\\output';
            readonly INPUT_DIRECTORY_NAME: fs.PathLike = '\\input';
            readonly ASSETS_DIRECTORY_NAME: fs.PathLike = '\\assets';
        };
    }
}

2
Könnte es sein, dass Ihre Antwort völlig irrelevant ist? Ich bin damit einverstanden, dass Downvoter erklären sollten, aber Ihre klare Antwort hat nichts mit der Frage zu tun ...
Manngo

@ Manngo danke für den Hinweis. Ehrlich gesagt würde ich die gleiche Frage wie OP stellen und ich verwende die von mir vorgeschlagene Lösung. Unsicher, warum es als irrelevant angesehen wird. Wenn Sie Zeit haben, erklären Sie dies bitte, damit ich die Antwort besser machen oder zumindest wissen kann, wo ich falsch liege. Ich verstehe leider nicht, warum dies keine vernünftige Lösung ist.
Dheeraj Bhaskar

-2

Wenn Sie natives JS verwenden möchten, bieten die anderen Antworten gute Lösungen.

Aber wenn Sie bereit sind, selbstreferenzierende Objekte zu schreiben wie:

{ 
  a: ...,
  b: "${this.a + this.a}",
}

Ich habe eine npm-Bibliothek namens self-referenced-object geschrieben , die diese Syntax unterstützt und ein natives Objekt zurückgibt.


1
Bitte vermeiden Sie nur Linkantworten . Antworten, die "kaum mehr als ein Link zu einer externen Site" sind, können gelöscht werden .
Quentin

@Quentin Haben Sie Vorschläge, wie ich meine Antwort verbessern kann? Die anderen Antworten auf diese Frage beziehen sich darauf, wie Sie möglicherweise selbstreferenzierende Objekte in nativem Javascript schreiben können, aber wenn Sie selbstreferenzierende Objekte mit einer Syntax schreiben möchten, die der Syntax in der ursprünglichen Frage des Posters ähnelt, denke ich, dass die Bibliothek das Ich schrieb, kann für andere nützlich sein, die nach einer Lösung suchen. Freut mich über Feedback.
Alex-E-Leon

Ein paar Dinge, die hier verbessert werden müssen. Erstens und am offensichtlichsten verwenden Sie die Template-Literal-Syntax ohne Back Ticks. bDer Wert Ihrer Immobilie sollte sein : ${this.a + this.a}. Zweitens, aber weniger wichtig, möchten Sie eine Zahl zurückgeben, keine Zeichenfolge, indem Sie so etwas wie verwenden parseInt. Zuletzt und vor allem, wenn ich dieses Beispiel ausprobiert habe, funktioniert es einfach nicht, aus dem gleichen Grund, den das OP fragt. Die thisRückgabe ist undefiniert, wenn eine eigene Objektdeklaration verwendet wird. @ alex-e-leon
Alec Donald Mather

@AlecDonaldMather - danke, dass du dir die Zeit genommen hast, einen Blick darauf zu werfen und Feedback zu geben! Wenn Sie an dem Projekt interessiert sind, ist es möglicherweise besser, diese Diskussion auf github zu verschieben, aber einige Ihrer Rückmeldungen zu beantworten: - Verwenden von Backticks: Wie in den vorherigen Kommentaren erwähnt, wird diese Syntax von JS nicht unterstützt und verwendet stattdessen Zeichenfolgen Hier ist eine Anzahl von Backticks erforderlich, um zu vermeiden, dass js versucht, "dies" aufzulösen, bevor das Objekt definiert wurde. Wenn eine Zahl zurückgegeben wird, sollte dies funktionieren, wenn a + b bereits Zahlen sind, da a + b eine Zahl zurückgibt, wenn sowohl a als auch b sind schon Zahlen.
alex-e-leon

Können Sie erklären, wie Sie versucht haben, die Bibliothek zu verwenden? Das sollte nicht passieren, aber vielleicht gibt es einen Randfall, den ich ausgelassen habe? Das heißt, diese Bibliothek löst das Problem nicht vollständig und hat ihre eigenen Kompromisse. Wenn Sie jedoch daran interessiert sind, mir zu helfen, es zu verbessern / zu verwenden, lassen Sie es mich wissen!
alex-e-leon
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.