Javascript – accès à la propriété de l'objet

Est-il possible de capturer une propriété (une) d'un objet ou une tentative d'accès?

Exemple:

J'ai créé un objet personnalisé Foo

 var Foo = (function(){ var self = {}; //... set a few properties return self; })(); 

Ensuite, il y a une action contre Foo – quelqu'un essaie d'accéder à la bar propriétés

 Foo.bar 

Existe-t-il un moyen (prototype, peut-être) de capturer cela? bar peut être indéfini sur Foo . Je pourrais suffire à capturer toute tentative d'accès à des propriétés indéfinies.

Par exemple, si la bar est indéfinie sur Foo , et Foo.bar est tenté, quelque chose comme:

 Foo.prototype.undefined = function(){ var name = this.name; //name of property they attempted to access (bar) Foo[name] = function(){ //...do something }; return Foo[name]; } 

Mais fonctionnel, contrairement à mon exemple.

Concept

 Foo.* = function(){ } 

Contexte

Si j'ai une fonction personnalisée, je peux écouter pour chaque fois que cette fonction est appelée (voir ci-dessous). Je me demande si c'est possible avec l'accès à la propriété.

 Foo = function(){}; Foo.prototype.call = function(thisArg){ console.log(this, thisArg); return this; } 

Cela sera possible dans ECMAScript6, et est possible maintenant sur Firefox, en utilisant le nouveau proxy . Jusque-là, non, je crains qu'il n'y ait aucun moyen d'accrocher la chaîne.

Cela m'a pris un moment, mais j'ai finalement trouvé ma réponse précédente à cette question. Voir cette réponse pour tous les détails sur les proxies et autres.

Voici l'exemple de proxy de cette réponse:

 var obj = new Proxy({}, { get: function(target, name) { if (!(name in target)) { console.log("Getting non-existant property '" + name + "'"); return undefined; } return target[name]; }, set: function(target, name, value) { if (!(name in target)) { console.log("Setting non-existant property '" + name + "', initial value: " + value); } target[name] = value; } }); console.log("[before] obj.foo = " + obj.foo); obj.foo = "bar"; console.log("[after] obj.foo = " + obj.foo); 

Live Copy (actuellement ne fonctionne que sur Firefox) | La source

Lors de l'exécution, ces sorties:

  Obtenir une propriété non existante 'foo'
 [Avant] obj.foo = indéfini
 Définition de la propriété non existante 'foo', valeur initiale: barre
 [Après] obj.foo = bar 

J'écrirai ceci sous l'hypothèse que vous essayez de déboguer quelque chose. Comme le dit Crowder, cela n'est disponible que sur les navigateurs les plus récents; C'est donc très utile pour tester le code qui fait quelque chose que vous ne le souhaitez pas. Mais, je l'supprime pour le code de production.

 Object.defineProperty(Foo, 'bar', { set: function() { debugger; // Here is where I'll take a look in the developer console, figure out what's // gone wrong, and then remove this whole block. } }); 

On a l'impression que le megawac m'a battu. Vous pouvez également trouver une documentation sur Mozilla sur les fonctionnalités ici .

Comme déjà répondu, il sera possible d'utiliser l'objet Proxy dans ECMAScript6. Pendant ce temps, selon vos besoins et votre conception globale, vous pouvez toujours y parvenir en mettant en œuvre quelque chose de similaire.

Par exemple

 function WrappingProxy(object, noSuchMember) { if (!this instanceof WrappingProxy) return new WrappingProxy(object); this._object = object; if (noSuchMember) this.noSuchMember = noSuchMember; } WrappingProxy.prototype = { constructor: WrappingProxy, get: function (propertyName) { var obj = this._object; if (propertyName in obj) return obj[propertyName]; if (this.noSuchMember) this.noSuchMember(propertyName, 'property'); }, set: function (propertyName, value) { return this._object[propertyName] = value; }, invoke: function (functionName) { var obj = this._object, args = Array.prototype.slice.call(arguments, 1); if (functionName in obj) return obj[functionName].apply(obj, args); if (this.noSuchMember) { this.noSuchMember.apply(obj, [functionName, 'function'].concat(args)); } }, object: function() { return this._object }, noSuchMember: null }; var obj = new WrappingProxy({ testProp: 'test', testFunc: function (v) { return v; } }, //noSuchMember handler function (name, type) { console.log(name, type, arguments[2]); } ); obj.get('testProp'); //test obj.get('nonExistingProperty'); //undefined, call noSuchMember obj.invoke('testFunc', 'test'); //test obj.invoke('nonExistingFunction', 'test'); //undefined, call noSuchMember //accesing properties directly on the wrapped object is not monitored obj.object().nonExistingProperty; 

Avec la nouvelle defineProperties , defineGetter et defineSetter étant ajouté à javascript, vous pouvez faire quelque chose de similaire. Il n'y a toujours pas de véritable façon de cacher __properties__ d'un objet. Je vous suggère de voir cet article .

 var obj = { __properties__: { a: 4 } } Object.defineProperties(obj, { "b": { get: function () { return this.__properties__.a + 1; } }, "c": { get: function (x) { this.__properties__.a = x / 2; } } }); obj.b // 2 obj.c // .5 

C'est le modèle classique qui devrait fonctionner dans n'importe quel environnement

 //lame example of a model var Model = function(a) { this.__properties__ = {a: a}; } Model.prototype.get = function(item) { //do processing return this.__properties__[item]; } Model.prototype.set = function(item, val) { //do processing this.__properties__[item] = val; return this; } var model = new Model(5); model.get("a") // => 5 

Comme les autres réponses ont mentionné, il n'existe actuellement aucun moyen d'intercepter des propriétés indéfinies.

Est-ce que cela serait acceptable?

 var myObj = (function() { var props = { foo : 'foo' } return { getProp : function(propName) { return (propName in props) ? props[propName] : 'Nuh-uh!' } } }()); console.log(myObj.getProp('foo')); // foo console.log(myObj.getProp('bar')); // Nuh-uh