故障评估';正在初始化函数定义(…在JavaScript中)

故障评估';正在初始化函数定义(…在JavaScript中),javascript,function,eval,Javascript,Function,Eval,我试图通过评估用户提供的字符串来构建一个简单的REPL。除了像“function f(){…}”这样的输入之外,它似乎在大部分情况下都有效,这对以后的evals中哪些函数是可见的没有影响。在玩了一会儿之后,我只能得出结论,我根本不懂eval。下面是一个演示一些神秘行为的小片段: var xeval = eval; function silly() {} eval("function good() {}"); function baffleMe() { eval("alsoGood

我试图通过评估用户提供的字符串来构建一个简单的REPL。除了像“function 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控制台或类似JSFIDLE的工具中执行代码时才会失败,但在嵌入脚本标记时不会失败。关于已接受答案的评论包含对此的解释。

我将尝试解释:

在全球范围内对货物进行评估:

good();         // Okay.
alsoGood();     // Okay.
notSoGood();    // ReferenceError: notSoGood is not defined
hope();         // Why does this even work?
Alsogood没有var定义,因此在全局范围内定义:

good();         // Okay.
alsoGood();     // Okay.
notSoGood();    // ReferenceError: notSoGood is not defined
hope();         // Why does this even work?
NotSoGood在功能范围内定义,因此不存在于全局范围内:

good();         // Okay.
alsoGood();     // Okay.
notSoGood();    // ReferenceError: notSoGood is not defined
hope();         // Why does this even work?
Hope在全球范围内通过eval的闭包引用进行评估,因此在全球范围内进行评估:

good();         // Okay.
alsoGood();     // Okay.
notSoGood();    // ReferenceError: notSoGood is not defined
hope();         // Why does this even work?
CrushedHope与hope相同,但在本例中应定义为愚蠢:

crushedHope();  // ReferenceError: silly is not defined

正如下面的评论中所提到的,当使用JSFIDLE和代码用
窗口包装时,问题中没有定义SPILL。onload

这是ECMAScript 5的一个特性。致:

如果间接使用eval函数,则从ECMAScript 5开始,通过eval以外的引用调用eval函数,它在全局范围而不是局部范围内工作;这意味着,例如,函数声明创建了全局函数,并且正在求值的代码不能访问调用它的范围内的局部变量

因此,直接调用
eval()
将在本地范围内创建函数。(使用
a=something
方法会自动创建一个全局变量。)但当您通过
xeval()
间接调用它时,它会得到全局求值


未定义的
愚蠢的
的最终结果取决于您正在评估的范围。如果您在控制台中,它的作用域似乎不同。如果您创建一个测试HTML页面,它可以正常工作。

请参阅
window.eval
global.eval
在节点中)和
eval
之间的区别:如果您要进行REPL,您应该将字符串evals放入
try catch
语句中,如果错误消息是
输入意外结束
,然后提示输入更多代码,直到
eval
生效,或者返回不同的错误。@user3026691
crushedhoope
不会产生我在Chrome和Firefox控制台中测试时所描述的错误。您在哪里看到这个错误?@user3026691啊,我看到了问题:如果您的代码不是全局的(例如,包装在
(function(){…})中)()
iLife,那么
silly
不是全局的。但是,
crushedhephope
是全局的,所以它在iLife中看不到本地定义的
silly
函数。它在JSFIDLE和Javascript控制台中都可以看到…0_o@user3026691您需要将您的小提琴“加载类型”设置从“onLoad”更改为“No wrap”。在
加载
事件侦听器函数中定义
愚蠢的
函数会使全局作用域无法访问该函数