Pregunta

Dado el siguiente fragmento de código de javascript en un ámbito:

var x = 10;

function sayx() {
  alert(x);
}

sayx();

Por supuesto, esperaría un cuadro de mensaje imprimiendo '10', podría hacer el anidamiento de múltiples funciones para interactuar con la forma en que se determina 'x', porque al resolver qué x es el entorno, sube la cadena de alcance.

Incluso puedes hacer un nivel de 'recompilación' con eval para inyectar nuevos ámbitos en tiempo de ejecución ... por ejemplo:

var x = 10;

function sayx() {
  alert(x);
}

function wrap(f) {
  return eval('(function() { var x = 20;(' + f + ')(); })');
}

wrap(sayx)();

Esto funciona porque la función tendrá su función toString llamada que devolverá la fuente "original" ... por lo tanto, esencialmente creamos una versión envuelta de la función que tiene un nuevo alcance que reemplaza a x .. el resultado será una alerta caja que imprime '20' y no '10'.

Sin embargo, en la superficie esto podría parecer que funciona pero la cadena de alcance está rota, el siguiente elemento de la cadena ya no es el mismo porque la función 'f' ahora está definida en una ubicación diferente ... aún peor es que la cadena de alcance que ha heredado podría contener muchas referencias a las que la función de llamada no debería tener acceso.

Entonces, ¿hay una forma más compatible y viable de inyectar un elemento de alcance? algo como:

function withScope(f, scope) { ??? }

---

var x = 10, y = 10;

function dothemath() {
  alert(x + y);
}

var haxthemath = withScope(dothemath, { x: 9000 });
haxthemath(); // 9010 not 20

Supongo que la respuesta es 'no', algunos pueden argumentar que hay problemas de 'seguridad' con este tipo de inyección de alcance, pero considerando que puedes hacer el truco de todos modos (aunque esté muy roto) no creo que sea ...

Los beneficios de esto serían que esencialmente puede falsificar sus propias pseudo variables.

Gracias de antemano.


Edite, solo aclare un poco, imagine que quería 'withScope' una función que tenía la siguiente cadena de alcance:

Window - window properties
Object - { var x = 10 }
Object - { var y = 5 + x }

Me gustaría poder recuperar una función que efectivamente tenía la misma cadena + el alcance que proporciono ... es decir:

withScope(somefunc, { foo: 'bar' })

Me lo daría

Window - window properties
Object - { var x = 10 }
Object - { var y = 5 + x }
Ext scope - { foo = 'bar' }

Todas las variables permanentes anteriores se encontrarían porque mi alcance extendido no dice nada sobre ellas.

¿Fue útil?

Solución

Si se refiere a las variables locales en la función y / o el cierre, por alcance, creo que la respuesta es no.

Puede cambiar el alcance de la palabra clave this utilizando functionName.call (scope, arg1, ...) o functionName.apply (scope, [arg1, ...]); Esto podría usarse junto con prototipos para crear cadenas similares a las que usted describe: si algo no se encuentra en las propiedades del objeto, se busca en su prototipo. Si la propiedad no está allí, se usa el siguiente prototipo de la cadena, etc.

Otros consejos

la respuesta que creo que estás buscando es la integrada "con" declaración.

Sin embargo, no recomendaría su uso, ya que está en desuso, y es muy probable que no exista en ecmascript 6

La única otra forma en la que creo que podrías hacer este tipo de cosas es desde dentro de la aplicación host, manipulando el entorno javascript desde afuera. O, si estás usando rhino, puedes hacerlo desde dentro de javascript, porque el enlace entre Java Apis y Javascript es exactamente lo mismo que en Rhino. Cuando Steve Yegge lo señaló por primera vez, me sorprendió. Manipule javascript desde fuera de javascript, pero desde dentro de javascript! ¡Es un genio!

Si estás atrapado dentro de un entorno de navegador, quizás puedas usar un intérprete de javascript escrito en javascript, como narciso.

¿Tal vez utilice el método incorporado toString de javascript para funciones?

function withScope(f, scope) {
    var toExec = "";
    for (var prop in scope) {
        toExec += "var " + prop + " = scope['" + prop + "'];"
    }
    toExec += "f = (" + f.toString() + ")";
    eval(toExec);
    return f;
}
var x = 10;
var f = function() {
    console.log(x);
};
withScope(f, {x: 20})();

Aunque parece una mala idea ...

Si quiere jugar con el alcance, puede disfrutar de la declaración let que se proporciona en Javascript 1.7. Versiones recientes de compatibilidad con Firefox let . / p>

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top