【发布时间】:2012-04-21 02:19:39
【问题描述】:
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());
我知道这不是一个很好的例子,但总体思路是使用动态范围来创建闭包。我认为这种模式有很大的潜力。
【问题讨论】:
-
写得很好,有趣的问题。虽然它要求一个客观的答案,除非有人展示它是如何做到的,我怀疑它会引发很多争论和主观答案,为什么它不能或不应该做。是什么让你想到这个问题的?
-
@ChrisWesseling - 我更新了我的问题以显示是什么让我发布了它。上述程序完全有效,适用于所有平台。我相信它有很大的潜力来创建类模式和许多其他东西。明智地使用它取决于公众。也许是使用
eval的唯一正当理由之一。 -
我想使用动态范围的原因是我可以将私有变量注入函数的范围。例如,在我上面的程序中,我还可以传递一个名为
uber的变量,它指向给定类的父类。这个变量应该可以被类范围访问,但它不应该被公众访问。因此,我不能只将它设置在类的实例上并称之为一天。因此,迂回的解决方法。 -
下面的代码对你有用吗?变量 x=1;函数 g () { print(this.x);这个.x=2; } 函数 f () { 变量 x=3 ;这个.g(); } 打印(x);
标签: javascript eval dynamic-scope