JavaScript posiada zakresy leksykalne, co oznacza, że zmienne nielokalne dostępne z poziomu funkcji są rozwiązywane na zmienne obecne w zasięgu rodziców tej funkcji, gdy została ona zdefiniowana. Jest to przeciwieństwo dynamicznego zakresu, w którym zmienne nielokalne uzyskiwane z funkcji są rozwiązywane na zmienne obecne w zasięgu wywołania tej funkcji, gdy jest wywoływana.Czy możliwe jest osiągnięcie dynamicznego zakresu w JavaScript bez odwoływania się do eval?
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?
Powyższe wydruków programów 1, a następnie 2 w lexically określania zakresów języka oraz drukuje 3, a następnie 1 w dynamicznego zakresu języka. Ponieważ JavaScript jest zawężona leksykalnie wypisze 1, a następnie 2, jak pokazano poniżej:
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
Chociaż JavaScript nie obsługuje Zakresy dynamiczne możemy wdrożyć go za pomocą eval
następująco:
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
Chciałbym wiedzieć, czy istnieje inny możliwy sposób osiągnięcia tego samego rezultatu bez odwoływania się do eval
.
Edit: To co staram się realizować bez użycia eval
:
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());
wiem, że nie jest to bardzo dobry przykład, ale ogólna idea jest użycie dynamiczne ustalanie zakresu w celu tworzenia zamknięć. Myślę, że ten wzór ma duży potencjał.
Ładnie napisane, interesujące pytanie. Choć prosi o obiektywną odpowiedź, chyba że ktoś pokaże, jak można to zrobić, podejrzewam, że wywoła to wiele dyskusji i subiektywnych odpowiedzi, dlaczego nie można lub nie należy tego robić. Co doprowadziło cię do tego pytania? –
@ChrisWesseling - zaktualizowałem swoje pytanie, aby pokazać, co skłoniło mnie do napisania tego. Powyższy program jest całkowicie poprawny i działa na wszystkich platformach. Wierzę, że ma duży potencjał do tworzenia wzorców klasowych i wielu innych rzeczy. To zależy od ogółu społeczeństwa, aby mądrze go używać. Być może jest to jeden z ważnych powodów używania 'eval'. –
Powodem, dla którego chcę korzystać z dynamicznego określania zakresu, jest możliwość wstrzyknięcia prywatnych zmiennych do zakresu funkcji. Na przykład w powyższym programie mogę również przekazać zmienną zwaną 'uber', która wskazuje na rodzica danej klasy. Ta zmienna powinna być dostępna dla zakresu klasy, ale nie powinna być publicznie dostępna. Dlatego nie mogę po prostu ustawić go na instancji klasy i nazwać go dniem. W ten sposób obejść rondo. –