Actualización de 2013 y 2015 (ver abajo la respuesta original de 2011) :
Esto cambió a partir de la especificación ES2015 (también conocido como "ES6"): JavaScript ahora tiene proxies . Los servidores proxy le permiten crear objetos que son servidores proxy verdaderos para (fachadas) de otros objetos. Aquí hay un ejemplo simple que convierte los valores de propiedad que son cadenas en mayúsculas en la recuperación:
"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}`); // "original.foo = bar"
console.log(`proxy.foo = ${proxy.foo}`); // "proxy.foo = BAR"
Las operaciones que no anula tienen su comportamiento predeterminado. En lo anterior, todo lo que anulamos es get
, pero hay una lista completa de operaciones en las que puede engancharse.
En la get
lista de argumentos de la función del controlador:
target
es el objeto que se representa (original
en nuestro caso).
name
es (por supuesto) el nombre de la propiedad que se está recuperando, que generalmente es una cadena pero también podría ser un Símbolo.
receiver
es el objeto que debe usarse como this
en la función getter si la propiedad es un descriptor de acceso en lugar de una propiedad de datos. En el caso normal, este es el proxy o algo que hereda de él, pero puede ser cualquier cosa ya que la trampa puede ser activada por Reflect.get
.
Esto le permite crear un objeto con la función de captador y configurador general que desea:
"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}`);
La salida de lo anterior es:
Obtención de propiedad inexistente 'foo'
[antes] obj.foo = undefined
Configuración de la propiedad inexistente 'foo', valor inicial: bar
[después] obj.foo = bar
Observe cómo obtenemos el mensaje "inexistente" cuando intentamos recuperarlo foo
cuando aún no existe, y nuevamente cuando lo creamos, pero no después de eso.
Respuesta de 2011 (ver arriba para actualizaciones de 2013 y 2015) :
No, JavaScript no tiene una característica de propiedad general. La sintaxis del descriptor de acceso que está utilizando se trata en la Sección 11.1.5 de la especificación, y no ofrece ningún comodín o algo así.
Por supuesto, podría implementar una función para hacerlo, pero supongo que probablemente no quiera usar en f = obj.prop("foo");
lugar de f = obj.foo;
y en obj.prop("foo", value);
lugar de obj.foo = value;
(lo que sería necesario para que la función maneje propiedades desconocidas).
FWIW, la función getter (no me molesté con la lógica del setter) se vería así:
MyObject.prototype.prop = function(propName) {
if (propName in this) {
// This object or its prototype already has this property,
// return the existing value.
return this[propName];
}
// ...Catch-all, deal with undefined property here...
};
Pero nuevamente, no puedo imaginar que realmente quieras hacer eso, debido a cómo cambia la forma en que usas el objeto.