Google Chrome上的ReferenceError但Firefox上没有(Browser Bug?)

时间:2016-08-12 15:52:40

标签: javascript google-chrome referenceerror

这段代码



eval(`
    let a = 0;
    function f() {}
    function g() { a; }
    console.log(f);
`);




在Firefox 48.0上正常运行,同时在Google Chrome 52.0.2743.116(64位)上导致Uncaught ReferenceError: f is not defined

如果

,它也适用于Google Chrome
  • eval未使用,或
  • eval内的代码包含{}
  • {li> a未在g或中引用
  • let已更改为var
  • 在代码之前添加了
  • "use strict"

这里发生了什么?

3 个答案:

答案 0 :(得分:5)

调整你的例子,你可以看到发生了什么,虽然命令有点矛盾,但它看起来像一个bug。将 a 定义为函数并将其记录而不是 f ,然后查看控制台。你会看到用 a,f和g 创建了一个闭包。由于g中引用了 a ,并且f和g应该彼此可见,因此它有点意义。但是eval在全球范围内起作用。因此,当您尝试访问它们时,您将得到未定义。就像这个闭包不能从任何地方访问。

尝试:

eval('let a = function(){}; function f() {};function g(){a;};console.dir(a);'); 

你会在控制台中看到这个:

<function scope>
    Closure
        a: function()
        f: function f()
        g: function g()

所有其他案例都会使情况更加清晰,并防止出现问题:

  • 未使用eval: 范围不匹配不太明显,
  • eval中的代码包含{} :变量已链接 通过块范围。
  • a未在g 中引用:如果变量不需要闭包 没有联系。
  • 让更改为var :全局范围中的var定义在 全球范围。所以不需要Closure
  • 在代码 之前添加
  • “use strict”:在eval中使用strict strict可以防止 要添加到全局范围的变量,所以再次“更容易” 处理。在让我们需要与全球职能联系之间没有不匹配。

答案 1 :(得分:2)

eval(`
    "use strict";
    let a = 0;
    console.log(f);
    function f(){
    }
    function g(){
        a;
    }
`);
  

在严格模式之外尚不支持块范围的声明(let,const,function,class)

答案 2 :(得分:1)

看起来像是a novel V8 bug!一个更小的测试用例是

eval(`
    var f;
    let a;
    ()=>a
`);
f;

当调用也有一个非常重要的词法声明时,变量范围的声明(包括顶级函数声明)无法从非严格eval调用中正确提升。