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).读完本文后,你应该清楚了解释器做了什么,为什么函数和变量能在声明前使用以及他们的值是如 ...
随机推荐
- 海外ubuntu,lamp,ftp,phpmyadmin配置
海外ubuntu,lamp,ftp,phpmyadmin配置 1. 更换源 1.1 clean /etc/apt/sources.list file 1.2 Ubuntu Sources List G ...
- windows 命令行打开浏览器
在命令行打开百度 start chrome www.baidu.com
- LANMP On CentOS 6
摘要 --在CentOS6.2-x86_64上安装Apache,Nginx,MySQL,Php 环境:最小化安装系统 yum install lrzsz mlocate.x86_64 wget lso ...
- 队列详解及java实现
导读 栈和队列是有操作限制的线性表. 目录 1.队列的概念.特点.存储结构. 2.栈队列的java实现. 概念 队列是一种在一端进行插入,而在另一端进行删除的线性表.1.队列的插入端称为队尾:队列的删 ...
- java多线程(八)-死锁问题和java多线程总结
为了防止对共享受限资源的争夺,我们可以通过synchronized等方式来加锁,这个时候该线程就处于阻塞状态,设想这样一种情况,线程A等着线程B完成后才能执行,而线程B又等着线程C,而线程C又等着线程 ...
- mysql数据库-------基础
一 数据库是什么 把文件存放于一台机器,然后将多台机器通过网络去访问这台机器上的文件,即共享这台机器上的文件,共享则意味着竞争,会发生数据不安全,需要加锁处理,为了远程访问并处理这台共享机器上的文件, ...
- SQL列中含有换行符的查找和替换方法
最近在获取数据时,发现程序读取的字段中含有\r\n字符,检查数据库表中的数据,发现是varchar字符串中包含了换行符.导入数据导致了这一情况出现. 回车换行 不同系统的行结尾符号并不同,如下: li ...
- COM学习(四)——COM中的数据类型
上一次说到,COM为了跨语言,有一套完整的规则,只要COM组件按照规则编写,而不同的语言也按照对应的规则调用,那么就可以实现不同语言间相互调用.但是根据那套规则,只能识别接口,并调用没有参数和返回类型 ...
- centos下安装最新版本git(通过master分支下载最新版)
centos6.7下安装最新版本git 本文参考:http://www.01happy.com/centos-install-latest-git/ 按照原博主所提供的思路安装可能会出现下列问题 解决 ...
- web前端教程:CSS 布局十八般武艺都在这里了
CSS布局 布局是CSS中一个重要部分,本文总结了CSS布局中的常用技巧,包括常用的水平居中.垂直居中方法,以及单列布局.多列布局的多种实现方式(包括传统的盒模型布局和比较新的flex布局实现), ...