geo*_*org 5 javascript scope eval
我们正在构建一个小型 REPL,用于eval在用户输入 JavaScript 表达式时对其进行求值。由于整个事情是事件驱动的,因此评估必须在单独的函数中进行,但必须在调用之间保留上下文(即所有声明的变量和函数)。我想出了以下解决方案:
function* _EVAL(s) {
while (1) {
try {
s = yield eval(s)
} catch(err) {
s = yield err
}
}
}
let _eval = _EVAL()
_eval.next()
function evaluate(expr) {
let result = _eval.next(expr).value
if (result instanceof Error)
console.log(expr, 'ERROR:', result.message)
else
console.log(expr, '===>', result)
}
evaluate('var ten = 10')
evaluate('function cube(x) { return x ** 3 }')
evaluate('ten + cube(3)')
evaluate('console.log("SIDE EFFECT")')
evaluate('let twenty = 20')
evaluate('twenty + 40') // PROBLEMRun Code Online (Sandbox Code Playgroud)
正如您所看到的,它对于函数作用域变量(var和function)工作得很好,但对于块作用域变量(let)则失败。
如何编写一个保留上下文的eval包装器,同时保留块范围的变量?
代码在浏览器中运行,DOM 和 Workers 完全可用。
应该提到的是,所需的函数必须正确处理副作用,即每一行代码,或者至少每个副作用,应该只执行一次。
链接:
JavaScript:在一台虚拟机中进行所有评估| https://vane.life/2016/04/03/eval-locally-with-persistent-context/
您链接的文章包含一种实际上有效的疯狂方法:在每次eval()调用期间,我们在该eval范围内创建一个新的闭包并将其导出,以便我们可以使用它评估下一个语句。
var __EVAL = s => eval(`void (__EVAL = ${__EVAL.toString()}); ${s}`);
function evaluate(expr) {
try {
const result = __EVAL(expr);
console.log(expr, '===>', result)
} catch(err) {
console.log(expr, 'ERROR:', err.message)
}
}
evaluate('var ten = 10')
evaluate('function cube(x) { return x ** 3 }')
evaluate('ten + cube(3)')
evaluate('console.log("SIDE EFFECT")')
evaluate('let twenty = 20')
evaluate('twenty + 40') // NO PROBLEM :DRun Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1361 次 |
| 最近记录: |