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