Google Chrome 上的 ReferenceError 但 Firefox 上没有(浏览器错误?)

ReferenceError on Google Chrome but not on Firefox (Browser Bug?)

这段代码

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 if

上也能正常工作

这里发生了什么?

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

Block-scoped declarations (let, const, function, class) not yet supported outside strict mode

调整你的例子你可以看到发生了什么,虽然命令有点矛盾,但它看起来像一个错误。将 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 中引用:如果变量 没有链接。
  • let 改为var:var在全局范围内定义在 全球范围。所以不需要关闭
  • "use strict"代码前加: use strict in eval prevents 要添加到全局范围的变量,所以再次 "easier" 到 处理。 let 需要与全局函数链接之间没有不匹配。

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

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

当调用也有非平凡的词法声明时,变量范围的声明(包括顶级函数声明)没有从非严格的 eval 调用中正确提升。