EC+VO+SCOPE for ES3
词法环境
词法作用域
词法作用域(lexcical scope)。即JavaScript变量的作用域是在定义时决定而不是执行时决定,也就是说词法作用域取决于源码。
词法环境
用于定义特定变量和函数标识符在ECMAScript代码的词法嵌套结构上的关联关系, 一个词法环境由一个环境记录项和可能为空的外部词法环境引用构成
词法环境 = 词法环境记录项 + 外部词法环境
外部词法环境是包含内部词法环境的词法环境, 外部词法环境可能有多个内部词法环境
环境记录项 = 声明式环境记录项 || 对象式环境记录项
执行环境
javascript引擎在执行每个函数实例时,都会创建一个执行环境(execution context)
执行环境中包含一个调用对象(call object), 调用对象是一个scriptObject结构(scriptObject是与函数相关的一套静态系统,与函数实例的生命周期保持一致),用来保存内部变量表varDecls、内嵌函数表funDecls、父级引用列表upvalue等语法分析结构。 varDecls和funDecls等信息是在语法分析阶段就已经得到,并保存在语法树中
函数实例执行时,会将这些信息从语法树复制到scriptObject上
Executable Code and Execution contents
“执行上下文”可以看做当前代码的运行环境或者作用域。
Types of Executable Code
Global Code:全局级别的代码 – 这个是默认的代码运行环境,一旦代码被载入,引擎最先进入的就是这个环境。
Function Code: 函数级别的代码 – 当执行一个函数时,运行函数体中的代码。
Eval Code: 在Eval函数内运行的代码,在特定的一次对 eval 的调用过程中,eval 代码作为该程序的 Global Code 部分。
每当调用执行一个函数时,引擎就会自动新建出一个函数上下文, 函数中函数也可能调用另一个函数,这样又创建一个执行环境, 也被称为上下文堆栈
执行上下文堆栈
ECMAScript的程序执行都可以看做是一个执行上下文堆栈[execution context (EC) stack]。堆栈的顶部就是处于激活状态的上下文, 堆栈最底部即为全局执行上下文环境[global execution context];
激活其它上下文的某个上下文被称为 调用者(caller) 。被激活的上下文被称为被调用者(callee) 。被调用者同时也可能是调用者(比如一个在全局上下文中被调用的函数调用某些自身的内部方法)。
当一个caller激活了一个callee,那么这个caller就会暂停它自身的执行,然后将控制权交给这个callee. 于是这个callee被放入堆栈,称为进行中的上下文[running/active execution context]. 当这个callee的上下文结束之后,会把控制权再次交给它的caller,然后caller会在刚才暂停的地方继续执行。在这个caller结束之后,会继续触发其他的上下文。一个callee可以用返回(return)或者抛出异常(exception)来结束自身的上下文。
执行上下文的建立过程
每当调用一个函数时,一个新的执行上下文就会被创建出来。然而,在javascript引擎内部,这个上下文的创建过程具体分为两个阶段:
建立阶段(发生在当调用一个函数时,但是在执行函数体内的具体代码以前)
- 建立变量,函数,arguments对象,参数
- 建立作用域链
- 确定this的值
代码执行阶段:
- 变量赋值,函数引用,执行其它代码
实际上,可以把执行上下文看做一个对象,其下包含了以上3个属性:
executionContextObj = {
variableObject: { /* 函数中的arguments对象, 参数, 内部的变量以及函数声明 */ },
scopeChain: { /* variableObject 以及所有父执行上下文中的variableObject */ },
this: {}
}
变量对象(variable object)
变量对象(缩写为VO)是一个与执行上下文相关的特殊对象,它存储着在上下文中声明的以下内容:
- 变量 (var, 变量声明)
- 函数声明 (FunctionDeclaration, 缩写为FD);
- 函数的形参 注: 只有全局上下文的变量对象允许通过VO的属性名称来间接访问
不同执行上下文中的变量对象
对于所有类型的执行上下文来说,变量对象的一些操作(如变量初始化)和行为都是共通的。从这个角度来看,把变量对象作为抽象的基本事物来理解更为容易。同样在函数上下文中也定义和变量对象相关的额外内容。
抽象变量对象VO (变量初始化过程的一般行为)
全局上下文变量对象GlobalContextVO
(VO === this === global), VO:
- 所有函数声明(FunctionDeclaration, FD)
- 所有变量声明(var, VariableDeclaration)
函数上下文变量对象FunctionContextVO
(VO === AO, 并且添加了arguments和形参), AO:
- 普通参数(formal parameters) 与特殊参数(arguments)对象
- 所有函数声明(FunctionDeclaration, FD)
- 所有变量声明(var, VariableDeclaration)
eval上下文
- eval会使用全局变量对象或调用者的变量对象(eval的调用来源)
- 变量声明在顺序上跟在函数声明和形式参数声明之后,但不会干扰AO中已经存在的同名函数声明或形式参数声明
- (function x() {}); 类似这样的函数表达式并不会影响AO
- 不管是使用var关键字(在全局上下文)还是不使用var关键字(在任何地方),都可以声明一个变量”。 请记住,这是错误的概念; 任何时候,变量只能通过使用var关键字才能声明。
变量的特性
- 变量有一个特性(attribute):{DontDelete},这个特性的含义就是不能用delete操作符直接删除变量属性
- eval上下文,变量没有{DontDelete}特性, 使用一些调试工具(例如:Firebug)的控制台测试该实例时,请注意,Firebug同样是使用eval来执行控制台里你的代码。因此,变量属性同样没有{DontDelete}特性,可以被删除。
作用域
javascript变量的作用域是在定义时决定而不是执行时决定,也就是说词法作用域取决于源码,编译器通过静态分析就能确定,因此词法作用域也叫做静态作用域(static scope)。但需要注意,with和eval的语义无法仅通过静态技术实现,所以只能说javascript的作用域机制非常接近词法作用域(lexical scope)
作用域链
在ECMAScript中,会用到内部函数[inner functions],在这些内部函数中,我们可能会引用它的父函数变量,或者全局的变量。我们把这些变量对象成为上下文作用域对象[scope object of the context]. 类似于上面讨论的原型链[prototype chain],我们在这里称为作用域链[scope chain]
作用域链与一个执行上下文相关, 用于在标识符解析中变量查找。 标示符[Identifiers]可以理解为变量名称、函数声明和普通参数
函数上下文的作用域链在函数调用时创建的,包含活动对象和这个函数内部的[[scope]]属性。其scope定义如下:Scope = AO + [[Scope]]
函数在被创建时保存外部作用域,是因为这个 被保存的作用域链(saved scope chain) 将会在未来的函数调用中用于变量查找。这种形式的作用域称为静态作用域[static/lexical scope]
在上下文中示意如下:
activeExecutionContext = {
VO: {...}, // or AO
this: thisValue,
Scope: [ // Scope chain
// 所有变量对象的列表
// for identifiers lookup
]
};
var x = 10; function foo() {
alert(x);
} (function () {
var x = 20;
foo(); // 10, but not 20
})();
在标识符解析过程中,使用函数创建时定义的词法作用域--变量解析为10,而不是20。此外,这个例子也清晰的表明,一个函数(这个例子中为从函数“foo”返回的匿名函数)的[[scope]]持续存在,即使是在函数创建的作用域已经完成之后。
补充说明
通过构造函数创建的函数的[[scope]]属性总是唯一的全局对象
在代码执行阶段有两个声明能修改作用域链。这就是with声明和catch语句
在代码执行过程中,如果使用with或者catch语句就会改变作用域链。而这些对象都是一些简单对象,他们也会有原型链。这样的话,作用域链会从两个维度来搜寻。
在解释执行阶段, 遇到变量需要解析时,会首先从当前执行环境的活动对象中查找, 如果没有找到而且该执行环境拥有者有prototype属性时, 则会从prototype链中查找, 否则将会按照作用域链查找;
end!
EC+VO+SCOPE for ES3的更多相关文章
- Execution Context(EC) in ECMAScript
参考资料 执行环境,作用域理解 深入理解JavaScript系列(2):揭秘命名函数表达式 深入理解JavaScript系列(12):变量对象(Variable Object) 深入理解JavaScr ...
- Scope Chain(作用域链)
本章,我们讨论一下ECMAScript中的作用域链 , 开门见山. 什么是作用域链 i.ECMAScript是允许创建内部函数的,甚至能从父函数中返回这些函数.作用域链正是内部上下文中所有变量对象(及 ...
- 深入理解JavaScript系列(14):作用域链(Scope Chain)
前言 在第12章关于变量对象的描述中,我们已经知道一个执行上下文 的数据(变量.函数声明和函数的形参)作为属性存储在变量对象中. 同时我们也知道变量对象在每次进入上下文时创建,并填入初始值,值的更新出 ...
- JavaScript内部原理实践——真的懂JavaScript吗?(转)
通过翻译了Dmitry A.Soshnikov的关于ECMAScript-262-3 JavaScript内部原理的文章, 从理论角度对JavaScript中部分特性的内部工作机制有了一定的了解. 但 ...
- javascript 执行环境,变量对象,作用域链
前言 这几天在看<javascript高级程序设计>,看到执行环境和作用域链的时候,就有些模糊了.书中还是讲的不够具体. 通过上网查资料,特来总结,以备回顾和修正. 要讲的依次为: EC( ...
- javascript 作用域链
最近想整理一下js执行代码的一些知识,如果有出错的地方还请指正. 执行环境(Execution Context) 所有的javascript代码都是在一个执行环境中被执行的.它只是一种机制,用来完成运 ...
- javascript 之变量对象-09
变量对象 变量对象:每个执行环境(执行上下文)都有一个对应的变量对象(variable object),环境中(执行上下文中)定义的所有变量.函数都保存在这个对象中. 在上篇中说到,当执行流执行一个函 ...
- javascript 之作用域链-10
前言 在<执行环境>文中说到,当JavaScript代码执行一段可执行代码时,会创建对应的执行上下文(execution context). 变量对象(Variable object,VO ...
- 你不知道的JavaScript--Item19 执行上下文(execution context)
在这篇文章里,我将深入研究JavaScript中最基本的部分--执行上下文(execution context).读完本文后,你应该清楚了解释器做了什么,为什么函数和变量能在声明前使用以及他们的值是如 ...
随机推荐
- Java编程学习知识点分享 入门必看
Java编程学习知识点分享 入门必看 阿尔法颜色组成(alpha color component):颜色组成用来描述颜色的透明度或不透明度.阿尔法组成越高,颜色越不透明. API:应用编程接口.针对软 ...
- 如何去除本地文件与svn服务器的关联
1.每个目录逐个去删除.svn文件夹 .svn属于隐藏文件夹,可通过操纵Windows文件资源管理器使隐藏文件可视,删除该文件,即可. 2.首先建立一个新文件,文件命名为remove-svn-fold ...
- Oracle添加记录的时候报错:违反完整性约束,未找到父项关键字
今天需要向一个没有接触过的一个Oracle数据库中添加一条记录,执行报错: 分析: 报错的根本原因:未找到父项关键字的原因是因为你在保存对象的时候缺失关联对象. 问题的解决思路:先保存关联对象后再保存 ...
- thinkphp5使用PHPExcel导入Excel数据
安装PHPExcel扩展类 地址:https://github.com/PHPOffice/PHPExcel ①通过composer安装 ②手动下载, 放在项目的extend目录下 代码中引入 由于P ...
- thinkinginjava学习笔记09_内部类
定义与创建 将一个类定义放在另一个类.方法.作用域.匿名类等地方,就是内部类:内部类只能由外部类对象创建(通过外部方法或者.new方法),内部类对象创建时必须已经有一个外部类对象,并且与之连接(在内部 ...
- CSS3 Media Queries 特性的妙用
第一招: 在网页中,pixel与point比值称为 device-pixel-ratio,普通设备都是1,iPhone 4是2,有些Android机型是1.5. 那么-webkit-min-devic ...
- CSS3 美女动画相框
把下面的内容放到一个body内,运行看一看:) <style> *{ margin:0; padding:0;} .bg1{ background-image:-moz-linear-gr ...
- Linux 常见命令示例【一】
查看端口占用 [查看目前系统上已在监听的网络联机及其pid netstat –tlnp] 文件挂载 Linux与windows文件传输(三方软件:secureCRT, WINscp) 1)sftp S ...
- Effective Java 第三版——19. 如果使用继承则设计,并文档说明,否则不该使用
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Solidity 中文文档 —— 第一章:Introduction to Smart Contracts
第一章:智能合约简介 粗略地翻译了 Ethereum 的智能合约开发语言的文档:Solidity.欢迎转载,注明出处. 有任何问题请联系我,本人微信:wx1076869692,更多详情见文末. 我是 ...