tag body attribute javascript object-properties

body - Javascript-captura el acceso a la propiedad del objeto



title html (5)

¿Es posible capturar cuando se accede a una (cualquiera) propiedad de un objeto, o se intenta acceder?

Ejemplo:

He creado el objeto personalizado Foo

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

Luego hay algo de acción contra Foo : alguien intenta acceder a la bar propiedades.

Foo.bar

¿Hay manera (prototipo, tal vez) de capturar esto? bar puede estar indefinida en Foo . Podría bastar con capturar cualquier intento de acceso a propiedades no definidas.

Por ejemplo, si la bar no está definida en Foo , y se intenta Foo.bar , algo como:

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

Pero funcional, a diferencia de mi ejemplo.

Concepto

Foo.* = function(){ }

Fondo

Si tengo una función personalizada, puedo escuchar cada vez que se llama a esta función (ver más abajo). Solo me pregunto si es posible con acceso a la propiedad.

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


Como mencionaron las otras respuestas, en este momento no hay manera de interceptar propiedades indefinidas.

¿Sería esto aceptable sin embargo?

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


Como ya se ha respondido, solo será posible usando el objeto Proxy en ECMAScript6. Mientras tanto, dependiendo de sus necesidades y diseño general, aún puede lograr esto implementando algo similar.

P.ej

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;


Con las nuevas defineProperties , defineGetter y defineSetter agregadas a javascript, puede hacer algo similar. Sin embargo, todavía no existe una forma verdadera de ocultar las __properties__ de un objeto. Te sugiero que veas este 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

Este es el tipo clásico de modelo que debería funcionar en cualquier entorno.

//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


Escribiré esto bajo el supuesto de que estás tratando de depurar algo. Como dijo Crowder, esto solo está disponible en los navegadores más nuevos; así que es muy útil para probar código que hace algo que no quieres que haga. Pero, lo quito por código de producción.

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. } });

Parece que Megawac me venció. También puede encontrar documentación de Mozilla sobre las características here .


Esto será posible en ECMAScript6, y es posible ahora mismo en Firefox, usando el nuevo proxy . Hasta entonces, no, me temo que no hay forma de engancharse a la cadena.

Me tomó un tiempo, pero finalmente encontré mi respuesta anterior a esta pregunta. Ver esa respuesta para todos los detalles sobre proxies y tal.

Aquí está el ejemplo de proxy de esa respuesta:

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);

Copia en vivo (actualmente solo funciona en Firefox) | Source

Cuando se ejecuta, eso produce:

Getting non-existant property ''foo'' [before] obj.foo = undefined Setting non-existant property ''foo'', initial value: bar [after] obj.foo = bar