LexicalEnviroment 对象和 [[Enviroment]] 之间的关系

据说每个代码块都有一个名为LexicalEnviroment该对象包含对外部作用域的引用和一个EnviromentRecord,其中包含有关当前作用域的信息。

另一方面,据说函数能够关闭,这要归功于它们[[Enviroment]]“记住函数定义位置”的构造。

我很困惑,object 和之间的关系是什么LexicalEnviroment[[Enviroment]]?它们是一回事吗?只有函数才有[[Enviroment]]构造吗?LexicalEnviroment那他们有对象吗?


人到中年有点甜
浏览 70回答 1
1回答

哆啦的时光机

博士它们都是Environment Record.LexicalEnvironment只是执行上下文的一个组成部分(函数不能有LexicalEnvironment),并且在调用函数时,LexicalEnvironment会为当前上下文创建一个新的,其[[OuterEnv]]字段被设置为 Function[[Environment]]字段。如果它是 Javascript,我想它会是:function handleInvokeFunction(func) {     const localEnv = new EnvironmentRecord();     localEnv.set('[[OuterEnv]]', func['[[Environment]]'])     calleeContext.lexicalEnvironment = localEnv; }免责声明:我不是这方面的专家。我只是想给你一个整体的想法,同时等待真正的专家在这里插话。环境记录Environment Records,用于记录(双关语意),包含执行功能所需的所有信息。例如,对于函数,它们包含变量声明和this值。当然,这是过于简单化了[src]。环境记录是一种规范类型,用于定义标识符与特定变量和函数的关联。每次评估此类代码时,都会创建一个新的环境记录来记录该代码创建的标识符绑定。关于环境记录的一件有趣的事情是,它们负责允许访问父变量,例如:// Environment Record "EnvA" const hello = "world"; if (1) {     // Environment Record "EnvB"     console.log(hello); } // outputs: world那是因为他们有一个名为 的字段[[OuterEnv]],它指向父环境。所以在上面的例子中,[[OuterEnv]]“EnvB”字段被设置为“EnvA” [src]。每个环境记录都有一个[[OuterEnv]]字段,该字段要么为空,要么是对外部环境记录的引用。每次运行时遇到一个新的代码块,它都会执行以下步骤[src]:创建一个新的环境记录。将该新环境的字段设置[[OuterEnv]]为旧(当前活动)环境。返回新环境执行上下文为了对所有块执行此操作,使用了执行上下文堆栈,它几乎类似于堆栈跟踪 [src]。不同之处在于,它不会仅在进入和退出函数时推送和弹出(就像堆栈跟踪那样),它只会更改进入或退出代码块时的最顶层条目(如 if 块)。执行上下文是一种规范设备,用于跟踪 ECMAScript 实现对代码的运行时评估。执行上下文堆栈用于跟踪执行上下文。执行上下文有一个LexicalEnvironment组件。需要跟踪该特定代码块中的变量。LexicalEnvironment:标识环境记录,用于解析代码在此执行上下文中所做的标识符引用。LexicalEnvironment 是一个环境记录,所以它有一个[[OuterEnv]]字段,这是运行时将相应更改的内容。LexicalEnvironment不属于函数对象。它只属于一个执行上下文。正在运行的执行上下文表示运行时当前正在执行的代码块[src]。正在运行的执行上下文始终是此堆栈的顶部元素。为了扩展上述步骤,当输入一个新的代码块时,这就是实际发生的事情[src]:创建具有适当值的新环境记录[[OuterEnv]](与之前相同的步骤)。使用新的环境记录作为运行记录。评估块内的所有行。恢复到以前的环境记录。返回结果并退出块。评论前面的例子,这就是会发生的事情:// This is Environment Record "EnvA".// The [[OuterEnv]] field for "EnvA" is null.// The running context LexicalEnvironment is "EnvA".const hello = "world";if (1) {    // Found new block    // Create a new Environment Record "EnvB".    // Set the "EnvB" [[OuterEnv]] field to    // the running context LexicalEnvironment.    // In this case, its "EnvA".    // Change the running context LexicalEnvironment to "EnvB".        // Evaluate all lines in the body using the new     // running context LexicalEnvironment.    // In this case, its "EnvB".        console.log(hello);        // Restore the previous running context LexicalEnvironment.    // Return the result.}// The running context LexicalEnvironment is Environment Record "A".// Since the inner block restored before returning, it didn't change.[[环境]]不过,还没有提到功能。这是不同的,因为函数可以在声明的范围之外执行。那就是[[Environment]]出现的地方。[[Environment]]:函数被关闭的环境记录。在评估函数的代码时用作外部环境。当块内有函数时,runningLexicalEnvironment被存储为[[Environment]]函数对象的字段。调用该函数时,该[[Environment]]字段用作[[OuterEnv]]。这就像该函数将它可以访问的所有变量存储在内部[[Environment]],并且在调用时,它可以使用再次访问它们[[Environment]]。与普通块的另一个区别是,在这种情况下,不是更改正在运行的执行上下文,而是创建一个新的并将其推送到堆栈。现在,尝试使用一个简单的代码:// This is Environment Record "EnvA".// The [[OuterEnv]] field for "EnvA" is null.// The running context LexicalEnvironment is "EnvA".const hello = "world";// Found a function, store the running context // into its [[Environment]] field, and do nothing else.function foo() {    // This block runs only after invoking bar().        // Create a new executing context "calleeContext".    // Create a new Environment Record "EnvB".    // Set the "EnvB" [[OuterEnv]] field, to the value    // stored inside [[Environment]]. In this case, its "EnvA".    // Set the LexicalEnvironment of "calleeContext" to "EnvB".    // Push "calleeContext" to the execution context stack.    // That makes "calleeContext" the running execution context.        // Evaluate all lines in the body    // using "calleeContext" LexicalEnvironment.    // In this case, its "EnvB".    // If a function is found here, set its    // [[Environment]] to "calleeContext" LexicalEnvironment.        console.log(hello); // works because `hello` was in "EnvA"        // Pop "calleeContext" from the execution context stack.    // "calleeContext" is no longer the running execution context.        // Return the result.}const bar = foo;bar();// The [[Environment]] of `bar` is still "EnvA".// The running context LexicalEnvironment is still "EnvA".由于该示例在声明函数的同一环境中调用该函数,因此它实际上并未使用“闭包”,但您可能已经明白了。综上所述尽管都是和[[Environment]],但它们用于不同的事物。LexicalEnvironmentEnvironment Records[[Environment]]保存LexicalEnvironment函数声明的位置。LexicalEnvironment是执行上下文的一个组成部分,它存储有关该特定代码块中的变量的信息。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript