简体   繁体   English

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

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

This piece of code 这段代码

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

works fine on Firefox 48.0 while causing Uncaught ReferenceError: f is not defined on Google Chrome 52.0.2743.116 (64-bit). 在Firefox 48.0上正常工作,同时导致Uncaught ReferenceError: f is not defined在Google Chrome 52.0.2743.116(64位)上定义。

It also works fine on Google Chrome if 它也适用于谷歌浏览器

  • eval is not used, or 不使用eval ,或
  • the code inside eval is surround with {} , or eval的代码包含{} ,或
  • a is not referenced in g , or a未在g引用,或
  • let is changed to var , or let改为var ,或
  • "use strict" is added before the code 在代码之前添加"use strict"

What's happening here? 这里发生了什么事?

Tweaking your example you can see what's happening, and while the command is a bit contradictory, it looks like a bug. 调整你的例子,你可以看到发生了什么,虽然命令有点矛盾,但它看起来像一个bug。 Define a as a function and log it instead of f , then have a look at the console. a定义为函数并将其记录而不是f ,然后查看控制台。 You'll see that a closure was created with a, f and g . 你会看到用a,f和g创建了一个闭包。 Since a is referenced in g, and f and g should be visible to each other, it makes a bit of sense. 由于a以g表示,并且f和g应该彼此可见,因此它有点意义。 But eval works in the global scope. 但是eval在全球范围内起作用。 So when you try to access them, you get undefined. 因此,当您尝试访问它们时,您将得到未定义。 It's like this closure cannot be accessed from anywhere. 就像这个闭包不能从任何地方访问。

Try: 尝试:

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

You'll see this in the console: 你会在控制台中看到这个:

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

All your other cases make the situation clearer, and prevent the issue: 所有其他情况都会使情况更加清晰,并防止出现问题:

  • eval is not used: the scope mismatch is less obvious, 不使用eval:范围不匹配不太明显,
  • the code inside eval is surround with {} : the variables are linked through a Block scope. eval中的代码包含{} :变量通过Block作用域链接。
  • a is not referenced in g : no need for a closure if the variables aren't linked. a未在g中引用 :如果变量未链接,则不需要闭包。
  • let is changed to var : var in the global scope is defined in the global scope. let更改为var :全局范围中的var在全局范围中定义。 So no Closure needed 所以不需要关闭
  • "use strict" is added before the code : use strict in eval prevents variables to be added to the global scope, so again, "easier" to handle. 在代码之前添加了“use strict” :在eval中使用strict可以防止变量被添加到全局范围,因此再次“更容易”处理。 No mismatch between having let needed to be linked with global functions. 让我们需要与全球职能联系起来之间没有不匹配。
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 在严格模式之外尚不支持块范围的声明(let,const,function,class)

Looks like it's a novel V8 bug ! 看起来这是一个新颖的V8错误 A more minimal test case is 一个更小的测试用例是

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

Variable-scoped declarations (which includes top-level function declarations) aren't getting properly hoisted out of non-strict eval calls when the call also has a nontrivial lexical declaration. 当调用也有一个非常重要的词法声明时,变量范围的声明(包括顶级函数声明)没有从非严格的eval调用中正确提升。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM