2011-08-08 9 views
24

¿Cómo emulo PHP __get() y __set() magic getter/setters en JavaScript? Mucha gente dice que esto es actualmente imposible. Estoy casi seguro de que es posible porque proyectos como nowjs (http://nowjs.com) hacen algo como esto.Monitorear todas las propiedades del objeto JavaScript (captadores y definidores de magia)

Sé que puede utilizar get y set, pero estos no funcionan cuando no está seguro de cuál será el nombre de la propiedad. Por ejemplo, , ¿qué ocurre si desea que un controlador de eventos se ejecute cuando se crea una nueva propiedad?

Ejemplo de lo que me gustaría hacer:

var obj = {}; 
notify(obj, function(key, value) { 
    //key is now the name of the property being set. 
    //value is the value of the property about to be set 
    console.log("setting " + key + " to " + value); 
}); 
obj.foo = 2; //prints "setting foo to 2" 
obj.bar = {a: 2}; //prints "setting bar to [Object]" 
//Notice that notify() worked even though 'foo' and 'bar' weren't even defined yet! 

(La pregunta es similar a las siguientes preguntas:

)

EDITAR: Parece que esta característica se denomina "proxies dinámicos" y debería aparecer en el estándar "Harmony" de ECMAScript (probablemente ES6). Puede leer más here. Se introduce un nuevo Objeto 'Proxy' con un par de métodos (es decir, Create() y createFunction()).

Se podría hacer esto:

//Constructing an object proxy (proto is optional) 
var proxy = Proxy.create(handler, proto); 
proxy.foo = 2; //Triggers 'set' function in the handler (read about it) 

fondo aquí: no funciona en la mayoría de los navegadores, sino una aplicación está disponible para Node.js: node-proxy.

+1

Esta función llamada proxies es parte de ECMAScript 6 no 5. – Raynos

+0

Buena captura. Revisé mi publicación. ¡Gracias! – BMiner

Respuesta

12

Mirando a través del código fuente nowjs, creo que lo hacen mediante la supervisión continua del objeto now y empujando los cambios entre el cliente y el servidor cada vez que se detectan. Sin embargo, admito que todavía no he descifrado por completo su código.

En un navegador, esto se haría con algunos hacks setInterval divertidos.

EDITAR: sí, eso es precisamente lo que hacen: line 368 del cliente now.js. Hacen some more tricks de modo que una vez que se detecta una propiedad nueva, getters y setters atrapan el acceso futuro a ella, pero esas modificaciones solo se realizan cada 1000 ms en un setTimeout.

Otra prueba de que esto es imposible en la corriente de JavaScript es que the proxies proposal for ECMAScript Harmony está explícitamente diseñado para permitir que tales escenarios, lo que implica muy fuertemente que no se puede hacer actualmente. Los últimos navegadores de Mozilla tienen a prototype proxies implementation, si es suficiente. Y aparentemente V8 is working to add support, que podría ser suficiente dependiendo de qué versión de V8 Node esté usando en estos días.

Edit2: oh fresco, en el ladoservidor hace parecer nowjs usar proxies! Lo que probablemente significa que están lo suficientemente maduros en Node para su uso. Vea lo que hacen en https://github.com/Flotype/now/blob/master/lib/proxy.js. O simplemente haga var Proxy = require("nodejs-proxy") y espere que sigan las especificaciones para que pueda aprovechar la documentación de MDC y de otros lugares.

+0

De acuerdo ... Puedo entender los hacks del lado del cliente, especialmente el b/c de problemas de compatibilidad del navegador. ¿Qué hay del lado del servidor? Me gusta, en Node.JS? ¿Crees que es posible hacer algo allí? – BMiner

+2

De hecho, acabo de editar mi publicación con mis hallazgos allí mientras comentabas :) – Domenic

0

¿Quizás this post podría ayudar ...? Sin embargo, eso es solo para propiedades específicas y navegadores basados ​​en Gecko ... Si necesita soporte para otros navegadores, tiene errores, pero podría mirar en el intercambio de propiedades. Aquí está el MSDN Page. Espero que ayude un poco ...

+0

Gracias por su ayuda. onpropertychange parece que solo es para objetos DOM. Esto debería funcionar para Objetos JS sin formato. – BMiner

2

En Firefox, puede usar Object.watch. Si nos fijamos en este hilo, Object.watch() for all browsers?, hay un ejemplo de usar algo así en todos los navegadores.

Ooops, me acabo de dar cuenta de que desea ver todas las propiedades, no una propiedad específica ... La solución anterior es observar una propiedad específica.

Cuestiones relacionadas