Czy możliwe jest osiągnięcie dynamicznego zakresu w JavaScript bez uciekania się do eval?

JavaScript ma zakres leksykalny, co oznacza, że ​​zmienne nielokalne uzyskiwane z funkcji są rozdzielane na zmienne obecne w zakresie rodziców tej funkcji, gdy została zdefiniowana. Jest to przeciwieństwo dynamicznego zakresu, w którym zmienne nielokalne, do których uzyskuje się dostęp z poziomu funkcji, są rozdzielane na zmienne obecne w zakresie wywoływania tej funkcji, gdy jest ona wywoływana.

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

Powyższy program drukuje 1, a następnie 2 w języku leksykalnym i drukuje 3, a następnie 1 w języku o dynamicznym zasięgu. Ponieważ JavaScript ma zasięg leksykalny, wydrukuje 1, a następnie 2, jak pokazano poniżej:

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

Mimo że JavaScript nie obsługuje dynamicznego zakresu, możemy go zaimplementowaćeval następująco:

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

Chciałbym wiedzieć, czy istnieje inny możliwy sposób osiągnięcia tego samego rezultatu bez uciekania się doeval.

Edytować: To jest to, co próbuję wdrożyć bez użyciaeval:

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

Wiem, że nie jest to bardzo dobry przykład, ale ogólny pomysł polega na wykorzystaniu dynamicznego zakresu do tworzenia zamknięć. Myślę, że ten wzór ma duży potencjał.

questionAnswers(7)

yourAnswerToTheQuestion