ECMASCRIPT 闭包 - 什么是 JavaScript 中的评估块?

ECMASCRIPT Closures - What is Evaluation block in JavaScript?

提问人: 提问时间:1/26/2023 最后编辑:Ivar 更新时间:1/27/2023 访问量:69

问:

https://tc39.es/ecma262/multipage/ecmascript-language-statements-and-declarations.html#sec-block-runtime-semantics-evaluation

14.2.2 运行时语义:评估

区块 : { }

  1. 返回空。

块 : { StatementList }

  1. 让 oldEnv 成为正在运行的执行上下文的 LexicalEnvironment。
  2. 设 blockEnv 为 NewDeclarativeEnvironment(oldEnv)。
  3. 执行 BlockDeclarationInstantiation(StatementList, blockEnv)。
  4. 将正在运行的执行上下文的 LexicalEnvironment 设置为 blockEnv。
  5. 设 blockValue 为 Completion(Evaluationof StatementList)。
  6. 将正在运行的执行上下文的 LexicalEnvironment 设置为 oldEnv。
  7. 返回?blockValue。

文档的这一部分是否是指 JavaScript 何时将焦点“放在”新的执行上下文上(例如,当您开始执行函数时)?

问题是因为我正在学习闭包。

JavaScript 范围 闭包 lexical-scope lexical-closures

评论

0赞 epascarello 1/26/2023
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/......
0赞 1/26/2023
嗨,@epascarello,所以文档指的是 JS 何时开始执行大括号(块)之间的任何代码,对吧?
0赞 1/26/2023
嗨,@T.J.克劳德,我问题中的陈述正确吗?

答:

2赞 T.J. Crowder 1/26/2023 #1

规范的这一部分描述了如何评估模块

文档的这一部分是否是指 JavaScript 何时“将焦点”放在新的执行上下文上......

差一点。包含语句的块会创建一个新的声明性词法环境(步骤 2),而不是一个新的执行上下文;然后,它将此新环境记录设置为正在运行的执行上下文的 LexicalEnvironment(步骤 4)。块的声明性词法环境用于包含块内的任何词法声明(即,使用 、 、 1 或 — 以复杂的方式 — 1,2 的声明),因为词法声明在 JavaScript 中是块范围的(尽管同样,对于声明来说,它很复杂)。但块不会创建新的执行上下文。letconstclassfunctionfunction

问题是因为我正在学习闭包。

这与闭包之间存在一些关系,因为闭包在创建它的当前环境记录上关闭。因此,如果您想知道在块内创建的闭包是否会关闭块内的绑定:是的,确实如此。


1 请注意,我们在这里谈论的是 / 声明,而不是 / 表达式。由于 / 表达式不会在它们出现的范围内创建绑定(松散地,变量),因此它们与本讨论无关。(回想一下,/ 声明是当 / 关键字出现在解析器期望语句的地方时;如果它出现在需要表达式的地方,则它是 / 表达式。例子:classfunctionclassfunctionclassfunctionclassfunctionclassfunctionclassfunction

   function ex1() { }
// ^^^^^^^^^^^^^^^^^^−−−−−−−−−−−−−−−−−−−−−−−− function declaration

   export default function() { }
//                ^^^^^^^^^^^^^^−−−−−−−−−−−−− function declaration (yes, really; this is the only place where a name isn't required on a function declaration)

   const ex2 = function() { };
//             ^^^^^^^^^^^^^^−−−−−−−−−−−−−−−− function expression

   const ex2 = function name() { };
//             ^^^^^^^^^^^^^^^^^^^−−−−−−−−−−− function expression

   someArray.forEach((e) => console.log(e));
//                   ^^^^^^^^^^^^^^^^^^^^^−−− function expression

   class Ex4 { }
// ^^^^^^^^^^^^^−−−−−−−−−−−−−−−−−−−−−−−−−−−−− class declaration

   export default class { }
//                ^^^^^^^^^−−−−−−−−−−−−−−−−−− class declaration (yes, really)

   const Ex5 = class { };
//             ^^^^^^^^^−−−−−−−−−−−−−−−−−−−−− class expression

   const Ex6 = class Name { };
//             ^^^^^^^^^^^^^^−−−−−−−−−−−−−−−− class expression

   const Ex7 = register(class { });
//                      ^^^^^^^^^−−−−−−−−−−−− class expression

2 关于声明与块的复杂关系:最初,声明创建了函数范围的全局变量,并且在块中声明函数没有指定的行为(这是对规范的允许扩展,并且它们由不同的 JavaScript 引擎 [甚至版本之间的相同引擎] 以不同的方式完成)。该规范的最新版本已经编纂了主要实现在块中的函数声明方面的重叠方式,其中包括一些块级语义。我在《JavaScript:新玩具》的第 3 章中详细介绍了血腥的细节,但实际上,一般来说,只是避免在块中使用函数声明(改用表达式);并非所有情况都有指定的行为,指定的行为可能会令人惊讶。functionfunctionvar

评论

0赞 1/26/2023
优秀的 @T.J. Crowder,所以只有 let、const 和 class 是块范围的?功能我明白,是你说的其他“特殊”+1
1赞 T.J. Crowder 1/26/2023
@GeorgeMeijer - 除了声明(很复杂)之外,yes、only 、 和 声明是块范围的; 函数中的声明具有函数作用域,无论它们是否在块中,全局作用域的声明都会创建全局变量(无论它们是否在块中)。functionletconstclassvarvar
1赞 T.J. Crowder 1/27/2023
@GeorgeMeijer - 是的,是的(块可以是独立的,也可以连接到流控制结构,如 、 等)。ifwhile
1赞 1/27/2023
太好了,非常感谢@T.J. Crowder。我一直认为函数被认为是块。标记为有用的答案
2赞 T.J. Crowder 1/27/2023
@Daniel - 块中的函数表达式没有函数声明所具有的复杂性,因为它们不会在它们出现的范围内创建绑定(松散地,变量)。只是函数声明。:-)