【问题标题】:What's the difference between "LexicalEnvironment" and "VariableEnvironment" in spec规范中的“LexicalEnvironment”和“VariableEnvironment”有什么区别
【发布时间】:2015-08-28 07:31:20
【问题描述】:

我正在阅读ECMAScript 2015 specification,并且多次使用术语“LexicalEnvironment”和“VariableEnvironment”。它们在表 23 中定义:

LexicalEnvironment:标识用于解析此执行上下文中的代码所做的标识符引用的词法环境。

VariableEnvironment:标识其 EnvironmentRecord 保存由此执行上下文中的 VariableStatements 创建的绑定的词法环境。

执行上下文的 LexicalEnvironment 和 VariableEnvironment 组件始终是 Lexical Environments。创建执行上下文时,其 LexicalEnvironment 和 VariableEnvironment 组件最初具有相同的值

所以,我想知道它们会有什么不同,以及各自用于哪些情况。谁能解释一下?

【问题讨论】:

  • Clarity on the difference between “LexicalEnvironment” and “VariableEnvironment” in ECMAScript 5 可能重复?他们的目的并没有真正改变,只是当前的词法环境被更频繁地交换(例如,每个块作用域)。
  • 是的,我以前读过它,但我还是有些麻烦。你说try {throw "some"} catch(x) { function y(){console.log(x, typeof x);} y(); },我在chrome下运行,但是没有throws a ReferenceError for x @Bergi
  • @SmallTownNE 谢谢,我更新了that answer。但是“有趣的事实”并不是这篇文章的主旨——主要的一点是当你进入一个块作用域时 LexicalEnvironment 会发生变化(例如catch,因为 ES6 也是普通块——对于letconst等)
  • 谢谢。我还有一些问题。我能总结一下LexicalEnvironment是静态的,VariableEnvironment是动态的吗?(因为我看了kangax's answer)@Bergi
  • 你认为VariableEnvironment 在同一个执行上下文中永远不会改变。但是kangax's answer 表示LexicalEnvironment 在同一个执行上下文中永远不会改变。这让我很困惑。你能解释一下吗? @贝尔吉

标签: javascript ecmascript-6


【解决方案1】:

我在github上将the question发到官方ECMA262组织,这是littledan的回答:

LexicalEnvironment 是一个局部词法作用域,例如,对于 let 定义的变量。如果您在 catch 块中使用 let 定义变量,则它仅在 catch 块中可见,为了在规范中实现它,我们使用 LexicalEnvironment。 VariableEnvironment 是 var 定义的变量之类的范围。 vars 可以被认为是“提升”到函数的顶部。为了在规范中实现这一点,我们给函数一个新的 VariableEnvironment,但是说块继承了封闭的 VariableEnvironment。

【讨论】:

    【解决方案2】:

    这很难。我将尝试用一些简单的例子来解释。所以一件重要的事情,在这个问题上也是要了解execution context

    词汇环境

    意味着你在代码中写东西的位置很重要。并非所有的编程语言都是这样,但 javascript 是。

    所以如果你有这样的功能

    function hello() {
        var myVar = 'hello';
    }
    

    现在变量myVar 在词法上位于函数内部。这实际上就是您正在编写的代码。 简而言之,如果谈论 lexical environment 意味着它是写在哪里以及它周围是什么。

    可变环境 每次调用函数时,都会创建一个新的执行上下文。因此,即使 myVar 被声明了 3 次(参见下一个示例),它们也不会相互接触。那是你谈论Variable Environment

    的时候

    function b() {
        var myVar;
        console.log('three', myVar) // three undefined 
                                    // cause myVar is newly declared in b()
                                    // but has no value
    }
    
    function a() {
        var myVar = 2;
        console.log('two', myVar) // two 2
        b();
    }
    
    var myVar = 1;
    console.log('one', myVar) // one 1
    a();
    console.log('four', myVar) // one 1

    现在你在哪里要求差异,我想这只是关于两件事的理论讨论。但lexical environment 也知道变量在内存中的位置。

    所以这实际上是您问题的答案。但我将展示更多示例,以确保误解可能会出错。

    因为在 javascript 中还有一个叫做 hoisting 的东西,如果你在错误的地方编写代码,它可能会给你带来错误。它可能有奇怪的行为。接下来的例子其实很简单,但都依赖于Lexical EnvironemntVariable EnvironmentExecution Contexthoisting

    console.log(myVar); // undefined
    var myVar = 'hello';
    console.log(myVar); // hello

    但是

    function a() {
        console.log(myVar) // gives Error myVar is not defined
    }
    a();

    但又一次:

    function a() {
        console.log(myVar); // undefined no Error
                            // cause it would take myVar from global
                            // execution context 
                            // but also no error cause we define it again
                            // in this function (hoisting)
        var myVar = 0;      // define myVar newly in this lexical environment
        console.log(myVar); // 0
    }
    
    var myVar = 'hello';
    a();
    console.log(myVar);     // hello

    但如果我们这样做的话

    function a() {
        myVar = 0;           // overwrite global myVar
        console.log(myVar); // 0
    }
    
    var myVar = 'hello';
    a();
    console.log(myVar);     // 0 did you expect myVar to be 0 ?

    【讨论】:

      猜你喜欢
      • 2013-02-08
      • 2010-12-25
      • 2011-04-01
      • 2019-04-20
      • 2020-03-16
      • 1970-01-01
      • 1970-01-01
      • 2019-04-18
      相关资源
      最近更新 更多