Aktualizacja z 2013 i 2015 r. (Poniżej przedstawiono oryginalną odpowiedź z 2011 r.) :
Zmieniło się to od specyfikacji ES2015 (znanej również jako „ES6”): JavaScript ma teraz serwery proxy . Serwery proxy umożliwiają tworzenie obiektów, które są prawdziwymi proxy dla innych obiektów (fasady na). Oto prosty przykład, który zamienia wszystkie wartości właściwości, które są ciągami, na wszystkie kapsle podczas pobierania:
"use strict";
if (typeof Proxy == "undefined") {
throw new Error("This browser doesn't support Proxy");
}
let original = {
"foo": "bar"
};
let proxy = new Proxy(original, {
get(target, name, receiver) {
let rv = Reflect.get(target, name, receiver);
if (typeof rv === "string") {
rv = rv.toUpperCase();
}
return rv;
}
});
console.log(`original.foo = ${original.foo}`);
console.log(`proxy.foo = ${proxy.foo}`);
Operacje, których nie zastępujesz, mają swoje domyślne zachowanie. W powyższym, wszystko, co nadpisujemy, to get
, ale istnieje cała lista operacji, do których można się podłączyć.
Na get
liście argumentów funkcji obsługi:
target
to obiekt, który ma zostać przekazany ( original
w naszym przypadku).
name
jest (oczywiście) nazwą pobieranej właściwości, która zwykle jest ciągiem znaków, ale może być również symbolem.
receiver
jest obiektem, który powinien być używany tak jak this
w funkcji pobierającej, jeśli właściwość jest akcesorem, a nie właściwością danych. W normalnym przypadku jest to proxy lub coś, co po nim dziedziczy, ale może to być wszystko, ponieważ pułapka może zostać uruchomiona przez Reflect.get
.
Pozwala to na utworzenie obiektu z wybraną funkcją pobierania i ustawiania catch-all:
"use strict";
if (typeof Proxy == "undefined") {
throw new Error("This browser doesn't support Proxy");
}
let obj = new Proxy({}, {
get(target, name, receiver) {
if (!Reflect.has(target, name)) {
console.log("Getting non-existent property '" + name + "'");
return undefined;
}
return Reflect.get(target, name, receiver);
},
set(target, name, value, receiver) {
if (!Reflect.has(target, name)) {
console.log(`Setting non-existent property '${name}', initial value: ${value}`);
}
return Reflect.set(target, name, value, receiver);
}
});
console.log(`[before] obj.foo = ${obj.foo}`);
obj.foo = "bar";
console.log(`[after] obj.foo = ${obj.foo}`);
Wynik powyższego to:
Pobieranie nieistniejącej właściwości „foo”
[przed] obj.foo = undefined
Ustawienie nieistniejącej właściwości „foo”, wartość początkowa: bar
[po] obj.foo = bar
Zwróć uwagę, jak otrzymujemy komunikat „nieistniejący”, kiedy próbujemy odzyskać, foo
gdy jeszcze nie istnieje, i ponownie, kiedy go tworzymy, ale nie później.
Odpowiedź z 2011 r. (Patrz powyżej dla aktualizacji z 2013 i 2015 r.) :
Nie, JavaScript nie ma właściwości typu catch-all. Składnia akcesora, której używasz, jest omówiona w sekcji 11.1.5 specyfikacji i nie oferuje żadnych symboli wieloznacznych ani czegoś podobnego.
Możesz oczywiście zaimplementować funkcję, aby to zrobić, ale przypuszczam, że prawdopodobnie nie chcesz używać f = obj.prop("foo");
zamiast f = obj.foo;
i obj.prop("foo", value);
zamiast obj.foo = value;
(co byłoby konieczne, aby funkcja obsługiwała nieznane właściwości).
FWIW, funkcja getter (nie zawracałem sobie głowy logiką ustawiającą) wyglądałaby mniej więcej tak:
MyObject.prototype.prop = function(propName) {
if (propName in this) {
return this[propName];
}
};
Ale znowu nie mogę sobie wyobrazić, że naprawdę chciałbyś to zrobić, ponieważ zmienia to sposób korzystania z obiektu.