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是词法作用域语言,因此它将按以下方式打印:
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());
我知道这不是一个很好的例子,但总体想法是利用动态作用域创建闭包。我认为这种模式有很大的潜力。
g
无法访问f
的局部变量,除非它在f
中定义。这就是我使用var g = eval(String(g))
的原因。在你的情况下,它就像我上面的第一个例子(没有动态作用域的那个)一样糟糕。更糟糕的是,你正在通过使用this
显式设置全局变量。 - Aadit M Shahvar f = function f () { this.x=3; g.call(this); } this.f = f; new f(); console.log(this.x);
} new test(); - Ken Russellthis
属性。我相信使用eval
是唯一的方法。然而,像每个程序员一样,我已经学会了拥抱语言而不是与之斗争。所以我不再需要动态作用域。我在函数式编程中找到了一个更好的解决方案,并利用我的新知识创建了一个非常小而高效的JavaScript库,用于面向对象和函数式编程-augment。=) - Aadit M Shah