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
eval
JavaScript は動的スコープをサポートしていませんが、次のように実装できます。
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());
あまり良い例ではないことは承知していますが、一般的な考え方は、動的スコープを使用してクロージャーを作成することです。このパターンの可能性は大きいと思います。