setters que profundización getters example and javascript scope closures local setter

que - javascript class getters and setters



Definir Setter/Getter para una variable local sin par: ¿imposible? (2)

Hay algunas preguntas previas sobre StackOverflow cuestionando cómo se accede a las variables locales a través de la cadena de alcance, como si quisiéramos hacer referencia a variables locales usando notación de corchetes y una cadena, necesitaríamos algo como __local__["varName"] . Hasta el momento, no he encontrado ni el método más travieso para lograr esto, y no he encontrado un método después de horas de explotar cada truco que conozco.

El objetivo es implementar getters / setters en variables arbitrarias sin parentesco. Object.defineProperties o __defineGet/Setter__ requieren un contexto para llamar. Para las propiedades en los contextos globales o de ventana puede lograr el objetivo de tener un setter / getter para referencias directas al objeto.

Object.defineProperty(this, "glob", {get: function(){return "direct access"}) console.log(glob); //"direct access"

Incluso en mis pruebas con una extensión personalizada que compilé en un Chromium modificado que se ejecuta antes de cualquier creación de ventana donde el contexto es el contexto global real, e incluso tratando de invocar this directamente en el contexto global bloquea mi programa, puedo sacarlo sin problemas:

Object.defineProperty(Object.prototype, "define", { value: function(name, descriptor){ Object.defineProperty(this, name, descriptor); } }; define("REALLYglobal", {get: function(){ return "above window context"; }});

Y luego está disponible en todos los fotogramas creados más tarde como un enrutamiento global a través del getter / setter especificado. El antiguo __defineGet/Setter__ también funciona en ese contexto sin especificar a qué llamarlo (aunque no funciona en Firefox, el método anterior sí lo hace).

Así que, básicamente, es posible definir guardias get / set para cualquier variable en un objeto, incluida la ventana / contexto global con llamada directa al objeto (no es necesario window.propname , simplemente propname ). Este es el problema de no poder hacer referencia a las variables de ámbito sin precedentes, ya que es el único tipo que puede estar en un alcance accesible pero no tiene un contenedor direccionable. Por supuesto, también son los más utilizados, así que no es un caso marginal. Este problema también trasciende la implementación actual de Proxies en ES6 / Harmony ya que es un problema específico al no poder direccionar el contenedor de un objeto local con la sintaxis del lenguaje.

La razón por la que quiero poder hacer esto es que es la única barrera que permite la sobrecarga de la mayoría de los operadores matemáticos para su uso en objetos complejos como matrices y algoritmos hash y derivar un valor resultante complejo. Necesito poder conectarme al setter en los casos en que se establece un valor en un tipo de objeto que configuré para la sobrecarga. No hay problema si el objeto puede ser global o puede estar contenido en un objeto primario, que probablemente sea con lo que iré. Todavía es útil con a.myObject , pero el objetivo es hacerlo lo más transparente posible.

No solo eso, sino que sería realmente útil poder lograr algo como esto:

var point3d = function(){ var x, y, z; return { get: function(){ return [x, y, z]; }, set: function(vals){ x=vals[0]; y=vals[1]; z=vals[2]; } }; };

(Esto es similar a la desestructuración de ES6, pero tiene aplicaciones más generales para implementar funcionalidades asociadas a la obtención / configuración y no solo al transporte de valores complejos). Incluso este código básico fallará completamente:

var x = {myname: "intercept valueOf and :set: to overload math ops!", index: 5}; x++; //x is now NaN if you don''t implement a setter somehow

No me importa qué tan hacky es la solución, en este punto es solo una curiosidad intensa para mí saber si se puede lograr, incluso si se requiere romper todas las mejores prácticas que existen. He bloqueado Firefox y Chrome unos cientos de veces en la búsqueda de esto hasta ahora haciendo cosas como redefinir / interceptar / modificar Object.prototype.valueOf/toString , Function.prototype Function.prototype.constructor , Function.prototype.call/apply , arguments.callee.caller , etc. con infinitos errores de recursividad y todo lo demás en intentos de establecer contextos de jurado de forma retroactiva. Lo único que he podido hacer funcionar es básicamente todo el asunto con eval y compilando fragmentos de código dinámicamente, lo cual es un puente demasiado lejos para que lo use. La única otra ruta remotamente exitosa fue en combinación con la predefinición de todas las variables locales en un contenedor, pero eso obviamente es muy intrusivo además de los problemas con el uso.


Esto es posible actualmente en entornos con Proxies. Ese sería el nodo> 0.6 ejecutado como node --harmony_proxies o> 0.7 con el node --harmony . Chromium Canary (no estoy seguro si está fuera de eso todavía) en about: flags en la parte inferior, javascript experimental. Firefox lo ha tenido por un tiempo sin banderas.

Entonces esto probablemente no funcionará cuando ES6 se vuelva más oficial, pero funciona hasta cierto punto ahora.

var target = (function(){ var handler = Proxy.create(Proxy.create({ get: function(r, trap){ return function(name,val,c,d){ if (trap === ''get'' || trap === ''set'') { name = val; val = c; } console.log(''"''+trap + ''" invoked on property "''+name+''" '' + (val?'' with value "''+val+''"'':'''')); switch (trap) { case ''get'': return target[name]; case ''set'': return target[name] = val; case ''has'': return name in target; case ''delete'': return delete target; case ''keys'': return Object.keys(target); case ''hasOwn'': return Object.hasOwnProperty.call(target, name); case ''getPropertyDescriptor'': case ''getOwnPropertyDescriptor'': return Object.getOwnPropertyDescriptor(target, name); case ''getPropertyNames'': case ''getOwnPropertyNames'': return Object.getOwnPropertyNames(target); case ''defineProperty'': return Object.defineProperty(target, name, val); } } } })) var target = { x: ''stuff'', f: { works: ''sure did'' }, z: [''overwritten?''] }; with (handler){ var z = ''yes/no''; if (x) { //x } else { x = true; } console.log(f.works); if (f.works) { f.works = true; delete f; } } return target })() // "getPropertyDescriptor" invoked on property "z" // "getPropertyDescriptor" invoked on property "z" // "getPropertyDescriptor" invoked on property "x" // "get" invoked on property "x" // "getPropertyDescriptor" invoked on property "console" // "getPropertyDescriptor" invoked on property "f" // "get" invoked on property "f" // sure did // "getPropertyDescriptor" invoked on property "f" // "get" invoked on property "f" // "getPropertyDescriptor" invoked on property "f" // "get" invoked on property "f" // "getPropertyDescriptor" invoked on property "f" target: { x: ''Stuff'', f: { works: true }, z: [''overwritten?''] }

Acertar o fallar y debe tener cuidado de no explotar su navegador simplemente mirando un Proxy en el depurador. Tuve que envolver esa cosa en un cierre para evitar que el proxy terminara en el alcance global o se bloqueara el marco cada vez. El punto es que funciona hasta cierto punto, donde nada más lo hace.


Parece que la respuesta es No. He estado buscando un comportamiento como este durante bastante tiempo. No he podido encontrar ninguna solución aceptable. Esta pregunta SO parece similar. Python tiene la palabra clave nice locals .