Mise à jour 2013 et 2015 (voir ci-dessous la réponse originale de 2011) :
Cela a changé depuis la spécification ES2015 (alias "ES6"): JavaScript a maintenant des proxies . Les proxies vous permettent de créer des objets qui sont de véritables proxies pour (façades sur) d'autres objets. Voici un exemple simple qui transforme toutes les valeurs de propriété qui sont des chaînes en majuscules lors de la récupération:
"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"
Les opérations que vous ne remplacez pas ont leur comportement par défaut. Dans ce qui précède, tout ce que nous remplaçons est get
, mais il y a toute une liste d'opérations auxquelles vous pouvez vous connecter.
Dans la get
liste des arguments de la fonction de gestionnaire:
target
est l'objet mandaté ( original
dans notre cas).
name
est (bien sûr) le nom de la propriété en cours de récupération, qui est généralement une chaîne mais peut également être un symbole.
receiver
est l'objet qui doit être utilisé comme this
dans la fonction getter si la propriété est un accesseur plutôt qu'une propriété de données. Dans le cas normal, c'est le proxy ou quelque chose qui en hérite, mais cela peut être n'importe quoi puisque le trap peut être déclenché par Reflect.get
.
Cela vous permet de créer un objet avec la fonction catch-all getter et setter que vous voulez:
"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}`);
Le résultat de ce qui précède est:
Obtenir la propriété inexistante «foo»
[avant] obj.foo = indéfini
Définition de la propriété inexistante 'foo', valeur initiale: bar
[après] obj.foo = bar
Notez comment nous obtenons le message "inexistant" lorsque nous essayons de le récupérer foo
alors qu'il n'existe pas encore, et à nouveau lorsque nous le créons, mais pas après cela.
Réponse de 2011 (voir ci-dessus pour les mises à jour 2013 et 2015) :
Non, JavaScript n'a pas de fonction de propriété fourre-tout. La syntaxe d'accesseur que vous utilisez est traitée dans la section 11.1.5 de la spécification, et n'offre aucun caractère générique ou quelque chose comme ça.
Vous pouvez, bien sûr, implémenter une fonction pour le faire, mais je suppose que vous ne voulez probablement pas utiliser f = obj.prop("foo");
plutôt que f = obj.foo;
et obj.prop("foo", value);
plutôt que obj.foo = value;
(ce qui serait nécessaire pour que la fonction gère des propriétés inconnues).
FWIW, la fonction getter (je ne me suis pas soucié de la logique du setter) ressemblerait à ceci:
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...
};
Mais encore une fois, je ne peux pas imaginer que vous souhaitiez vraiment faire cela, à cause de la façon dont cela change la façon dont vous utilisez l'objet.