2012-04-03 158 views
4

是否可以动态扩展javascript功能范围?我尝试没有成功如下:扩展javascript功能范围

function foo() 
{ 
    var bar = 12; 
    return function(x) 
    { 
     return eval(x); 
    } 
} 

var e = foo(); 

console.log(e("bar"));   // 12 
console.log(e("bar = 42;"));  // 42 
console.log(e("bar"));   // 42 
console.log(e("var baz = 99;")); // undefined 
console.log(e("baz"));   // ReferenceError: baz is not defined 

然而,如果我从线baz = 99删除var那么巴兹变量变成一个全球性的(这使我感觉良好):

... 
console.log(e("baz = 99;"));  // 99 
console.log(e("baz"));   // 99 
console.log(baz);    // 99 (so baz is just a global) 
+2

为什么你会想这个,这是肮脏的地狱 – Raynos 2012-04-03 19:32:56

+0

@Raynos:呵呵呵......可能是,但我不认为这是可怕的:我在写一个有趣的编译器瞄准的Javascript和实现模块我想知道如果使用函数作用域是一个可行的选项,同时保持模块“打开”(即允许从多个位置向模块添加名称,而不必一次性定义所有名称并使模块“密封“之后) – 6502 2012-04-03 19:37:19

+0

您是否考虑过使用对象?您不能使用函数作用域作为模块的容器 – Raynos 2012-04-03 19:53:21

回答

1

每次你打电话e("var baz = 4"),它创建一个函数调用堆栈上的变量,因此它不会在下次调用时可用。

如果您需要动态添加变量到范围,我会使用Rayno的建议,使用地图。 http://jsfiddle.net/UVSrD/

function foo() 
{ 
    var scope = {}; 
    return function(x) 
    { 
     return eval(x); 
    } 
} 


var e = foo(); 

console.log(e("scope.bar = 12")); // 12 
console.log(e("scope.bar")); // 12 
console.log(e("scope.baz = 14")); // 14 
console.log(e("scope.baz;")); // 14 
// Not a global 
console.log(typeof scope) // undefined 
+0

我明白为什么评估'var baz = 99;'没有工作......问题在于我想访问的范围是外部范围,而不是'foo'返回的函数。使用本地对象是一个选项,但意味着每次访问都使用双重查找(首先查找“范围”并查找变量或函数)。 – 6502 2012-04-03 20:19:48

+0

是的,作用域链是词法,所以你不能修改它。 – 2012-04-03 20:21:45

+0

我接受了,因为你最后的评论对我有意义。太糟糕了,没有一个预定义的词法变量绑定到封闭范围......可能这是故意的,因为使用固定大小的词法范围简化了实现或允许一些优化(但是我没有看到它们中的很多,示例eval必须能够访问所有词汇,实现被迫关闭整个范围内的闭包,而不仅仅是关闭的变量)。 – 6502 2012-04-03 23:11:18

0

你创造使用此代码封闭:

function foo() 
{ 
    var bar = 12; 
    return function(x) 
    { 
     return eval(x); 
    } 
} 

当你在酒吧通过你的覆盖已经被启动,以12杆的变量,我不知道是什么你试图完成,但使用闭包将保留外部函数变量。

+0

是的我知道我正在创建一个闭包,第二个'eval'正在修改一个捕获的变量。问题是,如果可能稍后添加更多的“捕获变量”和本地函数。 – 6502 2012-04-03 19:40:14

0

Eval将在所调用的任何位置运行。您看到的行为是因为在此行上:

console.log(e("var baz = 99;")); // undefined 

您在返回的函数的本地范围内创建var baz = 99。 var name = value的返回值;不是什么,你会得到未定义的。当您随后致电

console.log(e("baz"));   // ReferenceError: baz is not defined 

您返回一个新函数,其中baz尚未定义。

这是有点酷:http://www.bennadel.com/blog/1926-Exploring-Javascript-s-eval-Capabilities-And-Closure-Scoping.htm

+0

事实上,当我做了这个实验后,我才明白为什么评估'var baz'不起作用。我的问题是,如果有可能逃离一个层次并进入包含范围。 – 6502 2012-04-03 20:09:10

+0

我不认为这是可能的,因为这涉及修改范围两个层面。据我所知,没有办法直接影响范围。你可以创建一个新的对象并返回它,但我不相信你可以直接改变它创建的范围。 – 2012-04-03 20:45:05