我试图通过评估用户提供的字符串来构建一个简单的REPL。它似乎在很大程度上起作用,除了像"函数f(){...}"这样的输入,它们对未来的evals中可见的函数没有影响。在玩了一下之后,我只能得出结论,我根本不理解eval。这是一个简短的片段,展示了一些神秘的行为:
var xeval = eval;
function silly() {}
eval("function good() {}");
function baffleMe() {
eval("alsoGood = function() {}");
eval("function notSoGood() {}");
xeval("function hope() {}");
xeval("function crushedHope() { silly(); }");
}
baffleMe();
good(); // Okay.
alsoGood(); // Okay.
notSoGood(); // ReferenceError: notSoGood is not defined
hope(); // Why does this even work?
crushedHope(); // ReferenceError: silly is not defined
有人能解释这些结果吗? (可在最新的Chrome和Firefox中重现)
[编辑]
为了澄清,最后一次调用仅在代码在Javascript控制台或JSFiddle等工具中执行时才会失败,但在嵌入脚本标记时则不会。对已接受答案的评论包含对此的解释。
答案 0 :(得分:1)
我会尝试解释:
在全球范围内评估好:
good(); // Okay.
Alsogood没有var定义,因此正在全球范围内定义:
alsoGood(); // Okay.
NotSoGood在函数范围内定义,因此在全局范围内不存在:
notSoGood(); // ReferenceError: notSoGood is not defined
希望通过eval对全局范围的闭包引用进行评估,因此它在全局范围内进行了评估:
hope(); // Why does this even work?
CrushedHope与希望相同,但在这种情况下应该定义愚蠢:
crushedHope(); // ReferenceError: silly is not defined
正如下面的评论中所提到的,在使用JSFiddle和代码用window.onload
包装时,问题中未定义愚蠢。
答案 1 :(得分:1)
这是ECMAScript5的一项功能。致quote MDN:
如果您使用eval函数间接,则通过非eval之类的引用调用它,从ECMAScript 5开始,它在全局范围而不是本地范围内工作;这意味着,例如,函数声明创建全局函数,并且被评估的代码无法访问被调用的范围内的局部变量。
因此直接调用eval()
会在本地范围内创建函数。 (使用a=something
方法会自动创建一个全局。)但是当您通过xeval()
间接调用它时,它会被全局评估。
silly
未定义的最终结果取决于您正在评估的范围。如果您在控制台中,它似乎有不同的范围。如果您创建测试HTML页面,它可以正常工作。