【问题标题】:Javascript scoping changeJavascript 范围更改
【发布时间】:2017-11-04 22:24:13
【问题描述】:

我阅读了很多关于 javascript 作用域的内容,但似乎仍然无法理解为什么这段代码(左箭头指向的这一行)将 geval 作用域更改为全局作用域而不是函数作用域。 geval 在 test2 内部被调用,所以我认为它具有相同的范围..

const test2 = () => {
  var x = 2, y = 4;
  console.log(eval('x + y'));  // Direct call, uses local scope, result is 6
  var geval = eval; // equivalent to calling eval in the global scope
  console.log(geval('x + y')); // Indirect call, uses global scope, throws ReferenceError because `x` is undefined
  (0, eval)('x + y'); // another example of Indirect call
}

【问题讨论】:

  • 您可以将该代码复制并粘贴到问题中,而不是添加它的图像。
  • Eval 有一些奇怪的行为(在这种情况下也是如此)。最好的答案可能是:根本不要使用它。引用它对我来说也没有意义
  • 邪恶的评价是邪恶的。
  • @Roy — 您接受的答案归结为“因为规范说它应该这样工作”
  • @Roy There are a lot of reasons why images of code should not be used。我指出这一点并不意味着我知道答案。但它确实可以帮助那些这样做的人,或者想要复制/粘贴它以自己尝试,这最终也可以帮助你得到答案。报复性投票并不真正受到赞赏。如果您只是提到您添加了代码,我会很高兴撤消我的反对票。

标签: javascript


【解决方案1】:

以下摘录自 ECMA-262 第 7 版 (ECMAScript 2016) - 版本之间的节号有时会有所不同。

18.2.1.1 运行时语义:PerformEval(x, evalRealm, strictCaller, direct)

...

9。如果直接为真,那么
一个。让 lexEnv 为 NewDeclarativeEnvironment(ctx's LexicalEnvironment)。
乙。设 varEnv 为 ctx 的 VariableEnvironment。
10。别的,
一个。让 lexEnv 为 NewDeclarativeEnvironment(evalRealm.[[GlobalEnv]])。
乙。设 varEnv 为 evalRealm.[[GlobalEnv]]。

因此,对于间接调用(不是按名称调用 eval),您将到达第 10 步,该步骤调用 NewDeclarativeEnvironment(E),并将全局环境记录作为参数值。

NewDeclarativeEnvironment 在第 8.1.2.2 节中描述。正如预期的那样,这将为在eval 解析的脚本中使用let 定义的任何变量创建一个环境记录,并将该记录的“外部词法环境引用”设置为作为参数提供的环境记录。

步骤 10.b 将变量环境记录,对于使用 var 声明的命名函数和变量,设置为调用领域 eval 的全局环境记录,即浏览器文档中的 window。

简而言之,调用eval 间接为在被评估代码中声明的let 变量创建一个单独的环境记录,其下一个外部范围(词法引用)是全局对象,但使用var 的全局对象和命名函数声明。

如果您希望评估代码继承周围代码的范围,请使用名称 eval 作为函数引用进行直接调用。

9.a 和 10.a 的存在意味着使用 let 声明的变量在调用 eval 后不会保留,无论调用的类型是什么。


历史原因(编辑)

间接调用的行为可能是由于不推荐对对象调用eval 并从Object.prototype 中删除eval 属性。

来自 Object 数据类型方法的 JavaScript 1.2 参考:

eval     在指定对象的上下文中计算一串 JavaScript 代码。

在 JavaScript 的早期版本中对对象调用 eval 会导致代码评估,就好像它在 with (object) {} 语句中一样。

间接调用的规则将此行为替换为标准响应:如果将对象方法设置为 eval,则不会重新创建 object.eval 的先前行为,并且评估代码的范围是 @987654342 的全局对象 exceot @变量。这类似于使用 new Function 从文本创建函数的方式,其行为就像它是在全局范围内定义的一样。它还具有通过间接调用eval 看到的this 值是全局对象的效果(this 值驻留在环境记录中)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-06
    • 2016-08-25
    • 2015-09-14
    • 1970-01-01
    • 2010-11-06
    • 2018-05-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多