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 this
lö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?
javascript
object-literal
kpozin
quelle
quelle
foo.a
oderfoo.b
geändertfoo.c
werden. Dies kann erforderlich sein oder auch nicht.this
an das tiefste verschachtelte Objekt gebunden wird. ZB:... x: { get c () { /*this is x, not foo*/ } } ...
foo
sie als Variable deklariert wird undc
nur zum Zeitpunkt des Aufrufs ausgewertet wird, funktioniert die Verwendung vonfoo
insidec
im Gegensatz zuthis
(seien Sie jedoch vorsichtig)Sie könnten so etwas tun wie:
Dies wäre eine Art einmalige Initialisierung des Objekts.
Beachten Sie, dass Sie die Zuordnung tatsächlich den Rückgabewert
init()
zufoo
, also Sie habenreturn this
.quelle
delete this.init
vorher,return this
damit dasfoo
nicht verschmutzt istinit()
Aufruf direkt an das Literal angehängt, um einen einzelnen Ausdruck beizubehalten . Aber natürlich können Sie die Funktion separat von Ihnen aufrufen.Die offensichtliche, einfache Antwort fehlt der Vollständigkeit halber:
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:
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
delete
diese 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:
Oder natürlich, wenn Sie dies mehr als einmal tun müssen:
dann, wo Sie es verwenden müssen:
quelle
this
nur für Methoden dieses Objekts verfügbar ist und keine anderen Arten von Eigenschaften. Irgendeine Idee, wo ich das finden könnte? Vielen Dank!delete
10% schneller und gecko:delete
nur 1% langsamer.Instanziieren Sie einfach eine anonyme Funktion:
quelle
new Point(x, y)
außer dass die Funktion nicht zur Wiederverwendung benannt ist.var foo = function() { this.…; return this; }.call({});
was syntaktisch nicht viel anders, aber semantisch vernünftig ist.new
Schlüsselwort tatsächlich nicht bemerkt .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.
Im Pfeil
this
nimmt Getter den umgebenden lexikalischen Bereich auf .quelle
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 denget
Zucker verwenden können, ist er natürlich besser lesbar, aber die Fähigkeit war vorhanden.Einige Schließungen sollten sich damit befassen;
Alle darin deklarierten Variablen
foo
sind privat fürfoo
, 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üssenthis
, 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 zuweistfoo
. Am Ende geben Sie nur die Schnittstelle zurück, die Sie als Objekt mit derreturn {}
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 werdenfoo()
.quelle
Du könntest es so machen
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:
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
this
wie unten dargestellt verwenden würdenDann protokolliert der folgende Code 0, 1, 2 und gibt dann einen Fehler aus
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()
.quelle
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).
quelle
Sie können dies mithilfe des Modulmusters tun. So wie:
Mit diesem Muster können Sie je nach Bedarf mehrere foo-Objekte instanziieren.
http://jsfiddle.net/jPNxY/1/
quelle
}();
wäre, würde sie sich selbst ausführen und ein Objekt zurückgeben, keine Funktion. Außerdemfoo.c
ist eine Funktion, so schreibt es die Funktion und den nächsten Aufruf clobbers überfooObject.c()
fehlschlagen. Vielleicht ist diese Geige näher an dem, was Sie wollen (es ist auch ein Singleton, der nicht zum Instanziieren gedacht ist).Es gibt verschiedene Möglichkeiten, dies zu erreichen. das würde ich verwenden:
quelle
Nur zum Nachdenken - Platzieren Sie die Eigenschaften des Objekts außerhalb einer Zeitleiste:
Es gibt auch oben bessere Antworten . So habe ich den von Ihnen befragten Beispielcode geändert.
AKTUALISIEREN:
quelle
var foo = { get a(){return 5}, get b(){return 6}, get c(){return this.a + this.b} }
Jetzt können Sie einfachfoo.c
stattfoo.c()
:) (Fühlen Sie sich frei, dies in Ihre AntwortDas 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.
Die einfachste Lösung für berechnete Eigenschaften folgt (kein Heap, keine Funktionen, kein Konstruktor):
quelle
Die anderen hier veröffentlichten Antworten sind besser, aber hier ist eine Alternative:
init()
oder Code außerhalb des ObjektliteralSelbstausführende anonyme Funktionen und Fensterspeicher
Die Bestellung ist garantiert (
bar
vorherbaz
).Es verschmutzt
window
natürlich, aber ich kann mir nicht vorstellen, dass jemand ein Skript schreibtwindow.temp
, das hartnäckig sein muss. Vielleicht,tempMyApp
wenn 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.
quelle
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,
this
ohne dies zuerst zu tun,this
sich dies auf den äußeren Bereich bezieht ... der daswindow
Objekt sein wird.quelle
Wenn Ihr Objekt als eine Funktion geschrieben ist, die ein Objekt zurückgibt, UND Sie ES6-Objektattribut-Methoden verwenden, ist Folgendes möglich:
quelle
Ich verwende den folgenden Code als Alternative und es funktioniert. Und die Variable kann auch ein Array sein. (@ Fausto R.)
quelle
Hier ist eine nette ES6-Methode:
Ich benutze es, um so etwas zu tun:
quelle
Wie wäre es mit dieser Lösung? Dies funktioniert auch mit verschachtelten Objekten mit Array
quelle
Eine Option einwerfen, da ich nicht genau dieses Szenario behandelt habe. Wenn Sie nicht wollen ,
c
wenn aktualisierta
oder zub
aktualisieren, dann arbeitet ein ES6 IIFE gut.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:
Da ich eine Eigenschaft für festlegen
indexOfSelectedTier
und diesen Wert beim Festlegen derhasUpperTierSelection
Eigenschaft verwenden muss, berechne ich diesen Wert zuerst und übergebe ihn als Parameter an das IIFEquelle
Ein anderer Ansatz wäre, das Objekt zuerst zu deklarieren, bevor ihm Eigenschaften zugewiesen werden:
Damit können Sie den Objektvariablennamen verwenden, um auf die bereits zugewiesenen Werte zuzugreifen.
Am besten für
config.js
Datei.quelle
foo
die auf das betreffende Objekt verweist.Dies ist fast identisch mit der Antwort von @ slicedtoad, verwendet jedoch keine Funktion.
quelle
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
Lösung, wenn Objektliterale ausgereicht hätten
Ein anderes Beispiel
Hier in dieser Klasse können Sie mehrere relative Pfade untereinander kombinieren, was mit einem Objektliteral nicht möglich ist.
quelle
Wenn Sie natives JS verwenden möchten, bieten die anderen Antworten gute Lösungen.
Aber wenn Sie bereit sind, selbstreferenzierende Objekte zu schreiben wie:
Ich habe eine npm-Bibliothek namens self-referenced-object geschrieben , die diese Syntax unterstützt und ein natives Objekt zurückgibt.
quelle
b
Der 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 verwendenparseInt
. Zuletzt und vor allem, wenn ich dieses Beispiel ausprobiert habe, funktioniert es einfach nicht, aus dem gleichen Grund, den das OP fragt. Diethis
Rückgabe ist undefiniert, wenn eine eigene Objektdeklaration verwendet wird. @ alex-e-leon