繁体   English   中英

JavaScript 的词法环境如何维护嵌套块范围内的变量声明?

[英]How does JavaScript's lexical environment maintain variables declarations within nested block scopes?

我已经阅读了几篇关于执行上下文的更全面的文章,现在我有点困惑和头脑混乱。

为了使问题尽可能简短,避免长时间引用,我最好尝试通过一个专注于我无法获得的细节的示例来说明我的心理模型,以便您可以纠正我并指出错误。

下面是一个例子:

var tomato = 'global tomato';

{
  let tomato = 'block tomato';
  console.log(tomato); // 'block tomato'
}

console.log(tomato); // 'global tomato'

到目前为止,一切都清楚了。 当 JS 引擎创建一个执行上下文(在我们的例子中是全局的)时,第一行的var tomato声明被放置到一个Variable Environmentlet tomato块范围内的let tomato进入一个Lexical Environment 这解释了我们如何最终得到 2 个不同的西红柿。

现在,让我们添加另一个番茄,如下所示:

var tomato = 'global tomato';

{
  let tomato = 'block tomato';

  {
    console.log(tomato); // ReferenceError: Cannot access 'tomato' before initialization
    let tomato = 'nested block tomato';
  }

  console.log(tomato); // won't reach here
}

console.log(tomato); // won't reach here

ReferenceError不足为奇。 事实上,我们试图在变量被初始化之前访问它,这被称为临时死区。 这很好地表明 JS 已经在最嵌套的块中创建了另一个变量tomato 在我们引用它的那一刻,JS 也已经意识到这个tomato未被初始化。 否则,它会从外部作用域中抓取tomato ,这等于'block tomato'而不会抛出任何错误。 因此,让我们修复错误并交换行,如下所示:

var tomato = 'global tomato';

{
  let tomato = 'block tomato';

  {
    let tomato = 'nested block tomato';
    console.log(tomato); // 'nested block tomato'
  }

  console.log(tomato); // 'block tomato' - still 'block tomato'. Nothing has been overwritten.
}

console.log(tomato); // 'global tomato'

我想知道 JavaScript 如何管理这个嵌套最多的块。 因为到执行到达该行时:

let tomato = 'nested block tomato';

执行上下文的Lexical Environment已经包含在外部作用域中用'block tomato'值初始化的变量tomato 假设 JS 不只为代码块创建一个新的执行上下文(分别使用词法和变量环境)(这只是函数调用和全局脚本的情况,对吧?)并且显然,它不会覆盖现有的变量具有相同名称但来自嵌套块作用域的Lexical Environment 正如最后一段代码所示,其中创建了一个全新的独立变量来保存值'nested block tomato'

那么问题来了,这个变量究竟存储在哪里呢? 我的意思是执行上下文只有一个Lexical Environment ,但我们可能会创建许多嵌套的作用域来声明变量。 我正在努力想象这些变量的存储位置以及整个事情如何组合在一起。

假设 JS 不只为代码块创建一个新的执行上下文(分别使用词法和变量环境)(这只是函数调用和全局脚本的情况,对吧?)

这是一个错误的假设。

规格

词法环境是一种规范类型,用于根据 ECMAScript 代码的词法嵌套结构定义标识符与特定变量和函数的关联。 词法环境由环境记录和对外部词法环境的可能为空的引用组成。 通常,词法环境与 ECMAScript 代码的某些特定句法结构相关联,例如 FunctionDeclaration、BlockStatement 或 TryStatement 的 Catch 子句,并且每次评估此类代码时都会创建一个新的词法环境。

块语句创建了一个新的词法环境。

在 ECMAScript 中,词法作用域可以嵌套。

我的意思是执行上下文只有一个词法环境,但我们可能会创建许多嵌套的作用域来声明变量。

不,有一个词法环境用于……嗯……每个词法环境。 (毕竟,“范围”只是“环境”的不同术语。)

规范不强制实现者以任何特定方式实现这一点。 一种典型的方法可能是拥有环境的链接列表。

暂无
暂无

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

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