本文翻译自Dmitry Soshnikov的关于ECMAScript 系列的文章。其中涉及理论较多,如果想要更好的明白里面所讲的,要对ECMAScript 中相关概念本身有一点的基础,对于之前从未了解过得,推荐先到Dmitry Soshnikov文章中看完ES3系列的介绍,里面也有中文版本。此外,由于理论较多,难免会存在语言的上的生涩或者纰漏以及不规范之处,希望指正。这个系列分成了八个小篇章,可能需要读完才能更好的理解里面讲述的东西,同时,也可以可以结合ECMA-262-5规范来看本文。最后本翻译获得原作者Dmitry Soshnikov的认可,如果转载注明出处。
#介绍
本章将继续词法环境的介绍。之前的章节我们弄清楚了词法环境的通用理论。特别的我们已经知道了环境的概念与静态作用域和闭包的概念是密切相关的。
我们同样提到了 ECMAScript 使用链式环境框架模型(译注:也就是ES3中的作用域链)。这一部分将介绍词法环境在ECMAScript 中的完整实现。特别的,对于上一部分讲到的通用理论,我们会用ES中使用的专门术语再次叙述一遍。
先从定义开始,虽然在通用理论中已经给出了词法环境的定义,但这里的定义是与ECMA-262-5规范结合。
定义
正如在通用理论中提到的,环境是用来管理逻辑嵌套的代码块中的数据(变量,函数等)。这同样适合我们在ECMAScript对环境的用法。
从定义看:
词法环境定义了在ECMAScript 嵌套词法结构上标识符与变量值和函数值的关联关系。
同样,我们提到过名称(译注:也可以叫标识符或变量)和值的关联称为绑定。
ES(译注:ECMAScript,下同)中的词法环境由两部分组成:一个环境记录项和一个对外部环境的引用。这里一个环境的定义对应于我们上面讨论过的环境模型中的单个框架(译注:之前讨论的环境模型中,一个环境是框架的一个序列)。从而:
一个环境记录项记录了在关联词法作用域内创建的标识符绑定情形。
也就是说,一个环境记录项储存了在上下文中出现的变量声明(译注:也包括函数声明以及形参)。
看下面这个例子:
var x = 10;
function foo() {
var y = 20;
}
现在我们有了两个分别对应于全局上下文和foo函数上下文的抽象环境:
// 全局上下文对应的环境
globalEnvironment = {
environmentRecord: {
// built-ins:
Object: function,
Array: function,
// etc ...
// our bindings:
x: 10
},
outer: null // 外部环境引用的值为null
};
// foo函数的环境
fooEnvironment = {
environmentRecord: {
y: 20
},
outer: globalEnvironment
};
我们可以看到对外部环境的引用将当前环境和父级环境链接起来,而父环境同样会拥有对它自身外部环境的引用。在这里全局环境的外部引用被设置为null。
全局环境是这条作用域链的最后一环。这种形式与ES中的原型继承的工作机制类似:如果在对象本身不存在某个属性,那就去它的原型中搜索,找不到再去原型的原型搜索,以此类推,直到找到那个属性,或者一直到原型链的最末端。再回到环境:这里的变量(或标识符)可以类比对象的属性,对外部环境的引用与对象与原型的引用一样。
一个词法环境可能包含着多个内部词法环境。例如,如果一个函数包含两个嵌套函数,那每个嵌套函数的词法环境中指向外部环境的引用都是它们的外层函数的环境。看下面例子:
function foo() {
var x = 10;
function bar() {
var y = 20;
console.log(x + y); // 30
}
function baz() {
var z = 30;
console.log(x + y); // 40
}
}
// ----- Environments -----
// "foo" environmnet
fooEnvironment = {
environmentRecord: {x: 10},
outer: globalEnvironment
};
// "bar" 和"baz" 指向同一个外部环境引用,
//“foo”函数的环境
barEnvironment = {
environmentRecord: {y: 20},
outer: fooEnvironment
};
bazEnvironment = {
environmentRecord: {z: 30},
outer: fooEnvironment
};
ECMAScript 定义了两种环境记录项(译注:根据规范,记录项的类型还包括函数环境记录项,模块环境记录项已经全局环境记录项,但是这几种不作考虑,只是规范上的细分或者作为上面提到的子类)。对应两种不同的实现目标,下面我们将介绍它们的实现细节以便你完全理解,见词法环境:ECMAScript实现(二)—环境记录项。
原文链接
ECMA-262-5 in detail. Chapter 3.2. Lexical environments: ECMAScript implementation.