我正在尝试用 Javascript 编写一个 Read-Eval-Print-Loop。(它适用于基于 Web 的“自学 Javascript”平台。)我有一些最有效的东西,但我遇到了一个奇怪的闭包错误。
这是循环核心的简化版本。我这样写是因为我想使用闭包和延续来维护在以下创建的任何状态eval
:
// listing 1
var repl = function(result) {
return {
result:
result,
then:
function (expression, continuation) {
return continuation(eval(expression));
},
};
}
它几乎可以工作。例如,它正确地评估了表达式var x = 1
, x++
,的序列x
:
// listing 2
repl(eval('var x = 1')).then('x++', repl)
.then('x', repl)
.result
// evaluates to 2
所以表达式可以访问和修改之前声明的局部变量,而不会污染全局范围,这很棒。 但是变量声明(即var ...
)仅适用于链中的第一个表达式。 例如,表达式序列var x = 1
, var y = 2
,y
抛出一个y is not defined错误:
// listing 3
repl(eval('var x = 1')).then('var y = 2', repl)
.then('y', repl)
.result;
// throws "y is not defined"
我发现如果我repl
用它的定义替换每个实例,我可以避免这个错误,如下所示:
//listing 4
//
// same as listing 3, but repl is replaced with its
// definition from listing 1
function (result) {
return {
result:
result,
then:
function (expression, continuation) {
return continuation(eval(expression));
}
},
})(eval('var x = 1')).then(
'var y = 2',
function (result) {
return {
result:
result,
then:
function (expression, continuation) {
return continuation(eval(expression));
},
};
}
).then(
'y',
function (result) {
return {
result:
result,
then:
function (expression, continuation) {
return continuation(eval(expression));
},
};
}
).result
// evaluates to 2
这评估为 2。所以我想我可以通过eval
定义repl
每次迭代的定义来解决我的问题。但肯定有更好的解决方案……不是吗?
编辑:我尝试用 替换每个实例repl
,eval('('+repl+')')
但它没有解决问题。我错过了什么?