将运行时代码库中存在的作用域概念化为树是否准确?
var a;
function Foo() {
var b;
function Bar() {
var c;
}
function Bam() {
var d;
}
}
跟踪此代码中的范围:
global -> Foo --> Bar
|
-> Bam
或者这种概念化是否被封闭之类的东西打破了?
答案 0 :(得分:1)
是的,范围是一棵树。我想知道具有周期或DAG的范围图表意味着:)
关于闭包,范围仍然纯粹是词汇。即使您将闭包保存在变量上或将其存储在某个数组上,变量的范围仍然是最初定义函数的变量。
答案 1 :(得分:1)
问题中的图表是正确的。让我们用每个函数中可用的变量列表来理解它,
var a;
function Foo() {
var b;
# [a, b]
function Bar() {
var c;
# [a, b, c]
}
function Bam() {
var d;
# [a, b, d]
}
}
在Foo
中,a
可从更高的范围获得,并且其中已定义b
。 Bar
也可以访问a
,因为有关闭属性,它可以访问Foo
b
,但无法访问Bam
&# 39; s d
,因为它包含在Bam
中,在外面不可见。同样,Bam
无法访问Bar
c
。
实际上,当创建Foo
时,会创建一个新的词汇环境(其中包含环境记录和对外部的引用词法环境)及其中创建的所有变量将存储在环境记录中。由于Foo
没有任何外部环境,外部词汇环境将成为全球环境。
同样,当创建Bar
时,将创建一个新的词汇环境,它将外部词汇环境作为Foo
的词汇环境。因此,当在Bar
中访问的变量未在当前环境记录中定义时,将搜索Foo
的环境记录。
同样适用于Bam
。
引用ECMA Script 5.1 Specification,
词汇环境是一种规范类型,用于根据ECMAScript代码的词法嵌套结构定义标识符与特定变量和函数的关联。词汇环境由环境记录和外部词汇环境的可能空引用组成。通常,词汇环境与ECMAScript代码的某些特定语法结构相关联,例如TryStatement的FunctionDeclaration,WithStatement或Catch子句,并且每次评估此类代码时都会创建新的词法环境。
环境记录记录在其关联的词汇环境范围内创建的标识符绑定。
外部环境引用用于对Lexical Environment值的逻辑嵌套进行建模。 (内部)词汇环境的外部参考是对词汇环境的引用,它在逻辑上围绕着内部的词汇环境。当然,外部词汇环境可能有自己的外部词汇环境。词汇环境可以作为多个内部词汇环境的外部环境。例如,如果FunctionDeclaration包含两个嵌套的FunctionDeclarations,则每个嵌套函数的词法环境将使其外部词汇环境成为当前执行周围函数的词法环境。