JavaScript имеет лексическую область видимости, что означает, что нелокальные переменные, к которым осуществляется доступ из функции, разрешаются в переменные, присутствующие в родительской области этой функции, когда она была определена. Это контрастирует с динамической областью видимости, в которой нелокальные переменные, к которым осуществляется доступ изнутри функции, разрешаются в переменные, присутствующие в области вызова этой функции при ее вызове.
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?
Вышеупомянутая программа печатает 1, а затем 2 на языке с лексической областью видимости, и она печатает 3, а затем 1 на языке с динамической областью видимости. Поскольку JavaScript имеет лексическую область видимости, он будет печатать 1, а затем 2, как показано ниже:
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
Хотя JavaScript не поддерживает динамическую область видимости, мы можем реализовать его с помощью eval
следующим образом:
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
Я хотел бы знать, существует ли другой способ добиться того же результата, не прибегая к eval
.
Изменить: вот что я пытаюсь реализовать без использования 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());
Я знаю, что это не очень хороший пример, но общая идея состоит в том, чтобы использовать динамическую область видимости для создания замыканий. Я думаю, что у этого паттерна большой потенциал.
eval
. - person Aadit M Shah   schedule 08.04.2012uber
, которая указывает на родителя данного класса. Эта переменная должна быть доступна для класса, но не должна быть доступна для публики. Следовательно, я не могу просто установить его в экземпляре класса и назвать его днем. Таким образом, обходной путь. - person Aadit M Shah   schedule 08.04.2012g
не может получить доступ к локальным переменнымf
, если она не определена вf
. Вот почему я сделалvar g = eval(String(g))
. В вашем случае это похоже на мой первый пример выше (без динамической области видимости). Хуже того, вы явно устанавливаете глобальные переменные с помощьюthis
. - person Aadit M Shah   schedule 11.03.2013this
. Я почти уверен, что использованиеeval
- единственный способ сделать это. Однако, как и любой программист, я должен был научиться принимать язык, а не бороться с ним. Так что мне больше не нужна динамическая область видимости. Я нашел лучшее решение своей проблемы в функциональном программировании и использовал свои новые знания для создания очень небольшой и эффективной библиотеки JavaScript для объектно-ориентированного и функционального программирования - augment. знак равно - person Aadit M Shah   schedule 11.03.2013