Ich weiß, wie man Getter und Setter für Eigenschaften erstellt, deren Namen man bereits kennt, indem man so etwas macht:
// A trivial example:
function MyObject(val){
this.count = 0;
this.value = val;
}
MyObject.prototype = {
get value(){
return this.count < 2 ? "Go away" : this._value;
},
set value(val){
this._value = val + (++this.count);
}
};
var a = new MyObject('foo');
alert(a.value); // --> "Go away"
a.value = 'bar';
alert(a.value); // --> "bar2"
Meine Frage ist nun, ob es möglich ist, solche Catch-All-Getter und Setter wie diese zu definieren. Erstellen Sie also Getter und Setter für jeden Eigenschaftsnamen, der noch nicht definiert ist.
Das Konzept ist in PHP mit den Methoden __get()
und __set()
magic möglich ( Informationen hierzu finden Sie in der PHP-Dokumentation ). Ich frage mich also wirklich, ob es ein JavaScript gibt, das diesen Methoden entspricht.
Natürlich möchte ich im Idealfall eine browserübergreifende Lösung.
javascript
metaprogramming
getter-setter
Daiscog
quelle
quelle
Antworten:
Update 2013 und 2015 (siehe unten für die ursprüngliche Antwort von 2011) :
Dies wurde ab der ES2015-Spezifikation (auch bekannt als "ES6") geändert: JavaScript verfügt jetzt über Proxys . Mit Proxies können Sie Objekte erstellen, die echte Proxys für (Fassaden auf) anderen Objekten sind. Hier ist ein einfaches Beispiel, das alle Eigenschaftswerte, die Zeichenfolgen sind, beim Abrufen in alle Obergrenzen umwandelt:
Vorgänge, die Sie nicht überschreiben, haben ihr Standardverhalten. Oben überschreiben wir nur
get
, aber es gibt eine ganze Liste von Operationen, an die Sie sich anschließen können.In der
get
Argumentliste der Handlerfunktion:target
ist das Objekt, das vertreten wird (original
in unserem Fall).name
ist (natürlich) der Name der Eigenschaft, die abgerufen wird. Dies ist normalerweise eine Zeichenfolge, kann aber auch ein Symbol sein.receiver
ist das Objekt, das wiethis
in der Getter-Funktion verwendet werden soll, wenn die Eigenschaft eher ein Accessor als eine Dateneigenschaft ist. Im Normalfall ist dies der Proxy oder etwas, das von ihm erbt, aber es kann alles sein, da die Falle durch ausgelöst werden kannReflect.get
.Auf diese Weise können Sie ein Objekt mit der gewünschten Catch-All-Getter- und Setter-Funktion erstellen:
Die Ausgabe der oben genannten ist:
Beachten Sie, wie wir die Nachricht "nicht vorhanden" erhalten, wenn wir versuchen, sie abzurufen,
foo
wenn sie noch nicht vorhanden ist, und erneut, wenn wir sie erstellen, jedoch nicht danach.Antwort von 2011 (siehe oben für Updates 2013 und 2015) :
Nein, JavaScript verfügt nicht über eine Catch-All-Eigenschaftsfunktion. Die von Ihnen verwendete Accessor-Syntax wird in Abschnitt 11.1.5 der Spezifikation behandelt und bietet keinen Platzhalter oder ähnliches.
Sie könnten natürlich eine Funktion implementieren, um dies zu tun, aber ich vermute, Sie möchten wahrscheinlich nicht
f = obj.prop("foo");
eher alsf = obj.foo;
undobj.prop("foo", value);
statt verwendenobj.foo = value;
(was notwendig wäre, damit die Funktion unbekannte Eigenschaften verarbeitet).FWIW, die Getter-Funktion (ich habe mich nicht mit der Setter-Logik beschäftigt) würde ungefähr so aussehen:
Aber ich kann mir auch nicht vorstellen, dass Sie das wirklich wollen, weil es die Art und Weise ändert, wie Sie das Objekt verwenden.
quelle
Proxy
:Object.defineProperty()
. Ich habe die Details in meine neue Antwort eingefügt .Das Folgende könnte ein origineller Ansatz für dieses Problem sein:
Um es zu verwenden, sollten die Eigenschaften als Zeichenfolgen übergeben werden. Hier ist ein Beispiel, wie es funktioniert:
Bearbeiten: Ein verbesserter, objektorientierterer Ansatz, der auf dem basiert, was ich vorgeschlagen habe, ist der folgende:
Sie können es hier sehen .
quelle
Vorwort:
In der Antwort von TJ Crowder wird a erwähnt
Proxy
, das für einen Catch-All-Getter / Setter für Eigenschaften benötigt wird, die nicht existieren, wie vom OP gefordert. Abhängig davon, welches Verhalten bei dynamischen Gettern / Setzern tatsächlich gewünscht wird, ist einProxy
möglicherweise jedoch nicht erforderlich. oder möglicherweise möchten Sie eine Kombination von aProxy
mit dem verwenden, was ich Ihnen unten zeigen werde.(PS Ich habe
Proxy
in letzter Zeit gründlich mit Firefox unter Linux experimentiert und festgestellt, dass es sehr leistungsfähig ist, aber auch etwas verwirrend / schwierig zu bearbeiten und richtig zu machen. Noch wichtiger ist, dass es auch ziemlich langsam ist (zumindest in) Beziehung dazu, wie optimiert JavaScript heutzutage ist) - Ich spreche im Bereich von Deka-Vielfachen langsamer.)Um dynamisch erstellte Getter und Setter spezifisch zu implementieren, können Sie
Object.defineProperty()
oder verwendenObject.defineProperties()
. Das geht auch ganz schnell.Das Wesentliche ist, dass Sie einen Getter und / oder Setter für ein Objekt wie folgt definieren können:
Hier sind einige Dinge zu beachten:
value
Eigenschaft im Eigenschaftsdeskriptor (oben nicht gezeigt) nicht gleichzeitig mitget
und / oder verwendenset
. aus den Dokumenten:val
Eigenschaft außerhalb desObject.defineProperty()
Aufruf- / Eigenschaftsdeskriptors erstellt habe. Dies ist Standardverhalten.writable
auftrue
im Eigenschaftendeskriptor , wenn Sie verwendenget
oderset
.configurable
und diesenumerable
hängt jedoch davon ab, wonach Sie suchen. aus den Dokumenten:In diesem Sinne können diese auch von Interesse sein:
Object.getOwnPropertyNames(obj)
: ruft alle Eigenschaften eines Objekts ab, auch nicht aufzählbare (AFAIK ist dies der einzige Weg, dies zu tun!).Object.getOwnPropertyDescriptor(obj, prop)
: Ruft den Eigenschaftsdeskriptor eines Objekts ab, das Objekt, an dasObject.defineProperty()
oben übergeben wurde.obj.propertyIsEnumerable(prop);
: Rufen Sie für eine einzelne Eigenschaft einer bestimmten Objektinstanz diese Funktion für die Objektinstanz auf, um festzustellen, ob die bestimmte Eigenschaft aufzählbar ist oder nicht.quelle
__get
und__set
.defineProperty
behandelt diesen Fall nicht. Aus der Frage: "Erstellen Sie Getter und Setter für jeden Eigenschaftsnamen, der noch nicht definiert ist." (ihre Betonung).defineProperty
definiert Eigenschaften im Voraus. Die einzige Möglichkeit, das zu tun, wonach das OP gefragt hat, ist ein Proxy.obj.whateverProperty
, sodass die Bibliothek dies mit einem generischen Getter abfangen und den Eigenschaftsnamen the erhalten kann Benutzer versucht zuzugreifen. Daher die Forderung nach "Allround-Getter und Setter".das funktioniert bei mir
quelle
Function()
benutzen ist wie zu benutzeneval
. Setzen Sie einfach direkt die Funktionen als Parameter vondefineProperty
. Oder, wenn Sie aus irgendeinem Grund darauf bestehen, dynamisch zu erstellenget
undset
dann eine Funktion höherer Ordnung zu verwenden, die die Funktion erstellt und zurückgibt, wievar get = (function(propName) { return function() { return this[propName]; };})('value');