深入理解JavaScript系列(11) 执行上下文(Execution Contexts)


Posted in Javascript onJanuary 15, 2012

简介
从本章开始,我将陆续(翻译、转载、整理)http://dmitrysoshnikov.com/网站关于ECMAScript标标准理解的好文。

本章我们要讲解的是ECMAScript标准里的执行上下文和相关可执行代码的各种类型。

原始作者:Dmitry A. Soshnikov
原始发布: 2009-06-26
俄文原文:http://dmitrysoshnikov.com/ecmascript/ru-chapter-1-execution-contexts/

英文翻译:Dmitry A. Soshnikov.
发布时间:2010-03-11
英文翻译:http://dmitrysoshnikov.com/ecmascript/chapter-1-execution-contexts/

本文参考了博客园justinw的中文翻译,做了一些错误修正,感谢译者。
复制代码
定义
每次当控制器转到ECMAScript可执行代码的时候,即会进入到一个执行上下文。执行上下文(简称-EC)是ECMA-262标准里的一个抽象概念,用于同可执行代码(executable code)概念进行区分。

标准规范没有从技术实现的角度定义EC的准确类型和结构,这应该是具体实现ECMAScript引擎时要考虑的问题。

活动的执行上下文组在逻辑上组成一个堆栈。堆栈底部永远都是全局上下文(global context),而顶部就是当前(活动的)执行上下文。堆栈在EC类型进入和退出上下文的时候被修改(推入或弹出)。

可执行代码类型
可执行代码的类型这个概念与执行上下文的抽象概念是有关系的。在某些时刻,可执行代码与执行上下文完全有可能是等价的。

例如,我们可以定义执行上下文堆栈是一个数组:

ECStack = [];
每次进入function (即使function被递归调用或作为构造函数) 的时候或者内置的eval函数工作的时候,这个堆栈都会被压入。

全局代码
这种类型的代码是在"程序"级处理的:例如加载外部的js文件或者本地<script></script>标签内的代码。全局代码不包括任何function体内的代码。

在初始化(程序启动)阶段,ECStack是这样的:

ECStack = [ 
globalContext 
];

函数代码
当进入funtion函数代码(所有类型的funtions)的时候,ECStack被压入新元素。需要注意的是,具体的函数代码不包括内部函数(inner functions)代码。如下所示,我们使函数自己调自己的方式递归一次:
(function foo(bar) { 
if (bar) { 
return; 
} 
foo(true); 
})();

那么,ECStack以如下方式被改变:
// 第一次foo的激活调用 
ECStack = [ 
<foo> functionContext 
globalContext 
]; // foo的递归激活调用 
ECStack = [ 
<foo> functionContext ? recursively 
<foo> functionContext 
globalContext 
];

每次return的时候,都会退出当前执行上下文的,相应地ECStack就会弹出,栈指针会自动移动位置,这是一个典型的堆栈实现方式。一个抛出的异常如果没被截获的话也有可能从一个或多个执行上下文退出。相关代码执行完以后,ECStack只会包含全局上下文(global context),一直到整个应用程序结束。

Eval 代码
eval 代码有点儿意思。它有一个概念: 调用上下文(calling context),例如,eval函数调用的时候产生的上下文。eval(变量或函数声明)活动会影响调用上下文(calling context)。

eval('var x = 10'); (function foo() { 
eval('var y = 20'); 
})(); 
alert(x); // 10 
alert(y); // "y" 提示没有声明

ECStack的变化过程:
ECStack = [ 
globalContext 
]; // eval('var x = 10'); 
ECStack.push( 
evalContext, 
callingContext: globalContext 
); 
// eval exited context 
ECStack.pop(); 
// foo funciton call 
ECStack.push(<foo> functionContext); 
// eval('var y = 20'); 
ECStack.push( 
evalContext, 
callingContext: <foo> functionContext 
); 
// return from eval 
ECStack.pop(); 
// return from foo 
ECStack.pop();

也就是一个非常普通的逻辑调用堆栈。

在版本号1.7以上的SpiderMonkey(内置于Firefox,Thunderbird)的实现中,可以把调用上下文作为第二个参数传递给eval。那么,如果这个上下文存在,就有可能影响“私有”(有人喜欢这样叫它)变量。

function foo() { 
var x = 1; 
return function () { alert(x); }; 
}; var bar = foo(); 
bar(); // 1 
eval('x = 2', bar); // 传入上下文,影响了内部的var x 变量 
bar(); // 2

结论
这篇文章是后面分析其他跟执行上下文相关的主题(例如变量对象,作用域链,等等)的最起码的理论基础,这些主题将在后续章节中讲到。

其他参考

Javascript 相关文章推荐
用JavaScript和注册表脚本实现右键收藏Web页选中文本
Jan 28 Javascript
走出JavaScript初学困境—js初学
Dec 29 Javascript
JavaScript中的console.time()函数详细介绍
Dec 29 Javascript
js与jquery实时监听输入框值的oninput与onpropertychange方法
Feb 05 Javascript
JavaScript实现基于十进制的四舍五入实例
Jul 17 Javascript
js实现碰撞检测特效代码分享
Oct 16 Javascript
详解vue 中使用 AJAX获取数据的方法
Jan 18 Javascript
JavaScript的for循环中嵌套一个点击事件的问题解决
Mar 03 Javascript
vue.js做一个简单的编辑菜谱功能
May 08 Javascript
Angular5.0 子组件通过service传递值给父组件的方法
Jul 13 Javascript
react 应用多入口配置及实践总结
Oct 17 Javascript
JS如何使用剪贴板操作Clipboard API
May 17 Javascript
深入理解JavaScript系列(10) JavaScript核心(晋级高手必读篇)
Jan 15 #Javascript
深入理解JavaScript系列(9) 根本没有“JSON对象”这回事!
Jan 15 #Javascript
深入理解JavaScript系列(8) S.O.L.I.D五大原则之里氏替换原则LSP
Jan 15 #Javascript
深入理解JavaScript系列(7) S.O.L.I.D五大原则之开闭原则OCP
Jan 15 #Javascript
深入理解JavaScript系列(6):S.O.L.I.D五大原则之单一职责SRP
Jan 15 #Javascript
深入理解JavaScript系列(6) 强大的原型和原型链
Jan 15 #Javascript
深入理解JavaScript系列(4) 立即调用的函数表达式
Jan 15 #Javascript
You might like
4月1日重磅发布!《星际争霸II》6.0.0版本更新
2020/04/09 星际争霸
php的计数器程序
2006/10/09 PHP
php 文章采集正则代码
2009/12/28 PHP
PHP中的str_repeat函数在JavaScript中的实现
2013/09/16 PHP
php外部执行命令函数用法小结
2016/10/11 PHP
PHP unlink与rmdir删除目录及目录下所有文件实例代码
2018/02/07 PHP
php实现微信小程序授权登录功能(实现流程)
2019/11/13 PHP
javascript入门·对象属性方法大总结
2007/10/01 Javascript
Js中setTimeout()和setInterval() 何时被调用执行的用法
2013/04/12 Javascript
JS实现文件动态顺序载入的方法
2015/03/07 Javascript
js动态修改表格行colspan列跨度的方法
2015/03/30 Javascript
javaScript事件学习小结(四)event的公共成员(属性和方法)
2016/06/09 Javascript
js css实现垂直方向自适应的三角提示菜单
2016/06/26 Javascript
JavaScript实现的CRC32函数示例
2016/11/23 Javascript
Jquery与Bootstrap实现后台管理页面增删改查功能示例
2017/01/22 Javascript
nodeJS实现简单网页爬虫功能的实例(分享)
2017/06/08 NodeJs
[js高手之路]单例模式实现模态框的示例
2017/09/01 Javascript
JQuery元素快速查找与操作
2018/04/22 jQuery
详解angularjs4部署文件过大解决过程
2018/12/05 Javascript
JS前端面试必备——基本排序算法原理与实现方法详解【插入/选择/归并/冒泡/快速排序】
2020/02/24 Javascript
JavaScript 中的执行上下文和执行栈实例讲解
2021/02/25 Javascript
Python中的深拷贝和浅拷贝详解
2015/06/03 Python
django轻松使用富文本编辑器CKEditor的方法
2017/03/30 Python
Python爬虫PyQuery库基本用法入门教程
2018/08/04 Python
python中的socket实现ftp客户端和服务器收发文件及md5加密文件
2020/04/01 Python
python操作ini类型配置文件的实例教程
2020/10/30 Python
HTML5 中新的全局属性(整理)
2013/07/31 HTML / CSS
html5简介_动力节点Java学院整理
2017/07/07 HTML / CSS
俄罗斯香水在线商店:AromaCode
2019/12/04 全球购物
教师党员思想汇报
2014/01/06 职场文书
给男朋友的道歉信
2014/01/12 职场文书
安全教育月活动总结
2014/05/05 职场文书
平安工地建设方案
2014/05/06 职场文书
绿色小区申报材料
2014/08/22 职场文书
2014年党的群众路线活动个人整改措施
2014/10/28 职场文书
python用字节处理文件实例讲解
2021/04/13 Python