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 getliście argumentów funkcji obsługi:
targetto obiekt, który ma zostać przekazany ( originalw 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.
receiverjest obiektem, który powinien być używany tak jak thisw 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ć, foogdy 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.