2016-01-13 51 views
3

我想通过评估用户提供的字符串来构建一个简单的REPL。它似乎大部分工作,除了像“函数f(){...}”这样的输入,它对将来演示中哪些函数是可见的没有影响。在玩了一下之后,我只能得出结论,我根本不了解eval。下面是一段简短的片段,展示一些神秘的行为:麻烦评估函数定义(...在JavaScript中)

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

查看'window.eval'(Node中的'global.eval')和'eval' – elclanrs

+0

紧密相关:[global。eval无法访问词法范围中的变量](http://stackoverflow.com/q/31459180/710446) – apsillers

+0

如果您要创建REPL,则应该将字符串evals放入'try catch'语句中,并且如果错误消息是'意外的输入结束',那么提示输入更多的代码,直到'eval'工作,或者返回一个不同的错误。 –

回答

1

我会尽量解释:

好是在全球范围内评估:

good();   // Okay. 

Alsogood有没有变种的定义,因此正在对全球范围内定义:

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当傻是在问题未定义。

+0

但是为什么在粉碎的希望中不可见? – user3026691

+0

@ user3026691'crushedHope'不会产生您在Chrome和Firefox控制台中测试时描述的错误。你在哪里看到这个错误? – apsillers

+1

@ user3026691啊,我看到了问题:如果你的代码不是全局的(例如,封装在一个'(function(){...})()'IIFE中,那么'傻'不是全局的。 ,'crushedHope' *是全局的,所以它不能在IIFE内部看到你本地定义的'愚蠢'功能。 – apsillers

1

这是ECMAScript5的一项功能。要quote MDN

如果您使用eval函数间接,经由比其他的eval参考调用它,为的ECMAScript 5的它工作在全球范围内,而不是本地范围;这意味着,例如,函数声明创建全局函数,并且被评估的代码无法访问被调用范围内的局部变量。

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

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