É 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.

questionAnswers(7)

yourAnswerToTheQuestion