É possível alcançar escopo dinâmico em JavaScript sem recorrer a eval?
O JavaScript tem escopo léxico, o que significa que variáveis não locais acessadas de dentro de uma função são resolvidas para variáveis presentes no escopo dos pais dessa função quando foi definida. Isso está em contraste com o escopo dinâmico em que variáveis não locais acessadas de dentro de uma função são resolvidas para variáveis presentes no escopo de chamada dessa função quando ela é chamada.
<code>x=1 function g () { echo $x ; x=2 ; } function f () { local x=3 ; g ; } f # does this print 1, or 3? echo $x # does this print 1, or 2? </code>
O programa acima imprime 1 e, em seguida, 2 em uma linguagem com escopo léxico, e imprime 3 e, em seguida, 1 em uma linguagem com escopo dinâmico. Como o JavaScript tem um escopo léxico, ele imprimirá 1 e 2 conforme demonstrado abaixo:
<code>var print = x => console.log(x); var x = 1; function g() { print(x); x = 2; } function f() { var x = 3; g(); } f(); // prints 1 print(x); // prints 2</code>
Embora o JavaScript não suporte o escopo dinâmico, podemos implementá-lo usandoeval
do seguinte modo:
<code>var print = x => console.log(x); var x = 1; function g() { print(x); x = 2; } function f() { // create a new local copy of `g` bound to the current scope // explicitly assign it to a variable since functions can be unnamed // place this code in the beginning of the function - manual hoisting var g_ = eval("(" + String(g) + ")"); var x = 3; g_(); } f(); // prints 3 print(x); // prints 1</code>
Eu gostaria de saber se existe outra maneira possível de alcançar o mesmo resultado sem recorrer aeval
.
Editar: É isso que estou tentando implementar sem usareval
:
<code>var print = x => console.log(x); function Class(clazz) { return function () { var constructor; var Constructor = eval("(" + String(clazz) + ")"); Constructor.apply(this, arguments); constructor.apply(this, arguments); }; } var Rectangle = new Class(function () { var width, height; constructor = function (w, h) { width = w; height = h; }; this.area = function () { return width * height; }; }); var rectangle = new Rectangle(2, 3); print(rectangle.area());</code>
Eu sei que não é um exemplo muito bom, mas a idéia geral é usar o escopo dinâmico para criar fechamentos. Eu acho que esse padrão tem muito potencial.