首页
Javascript
Html
Css
Node.js
Electron
移动开发
小程序
工具类
服务端
浏览器相关
前端收藏
其他
关于
公司注册

ECMA-262-3 in detail——第一章:执行上下文

2015年01月10日 发布 阅读(1909) 作者:Jerman

原文(英译)地址:ECMA-262-3 in detail. Chapter 1. Execution Contexts.

介绍 | Introduction

在这一章里,我们将会讨论ECMAScript中的执行上下文(execution context)以及与它们相关的可执行代码(executable code)的类型。

定义 | Definitions

每当控制转移到ECMAScript的可执行代码上时,它就进入了一个执行上下文。

执行上下文(Execution context,简称EC)是ECMA-262规范中使用的一个抽象概念,用于表示和区分一段可执行代码。

在标准中并没有从技术实现的角度定义EC的精确结构和类型;这是实现ECMAScript标准的引擎的问题。

逻辑上,一族激活的执行上下文符合栈(stack)的概念。栈的底部总是一个全局上下文,而顶部是一个当前(激活)的执行上下文,栈在进出不同的EC时改变(push/pop)。

可执行代码的类型 | Types of executable code

可执行代码的类型(type of an executable code)的概念与抽象概念执行上下文相关的。当说到代码的类型时,在某些时候可能指的就是执行上下文。

例如,我们将执行上下文的栈定义为一个数组:

  1. ECStack = [];

每次进入一个函数时(即使是函数的递归调用或作为构造式调用时)栈就被pushed,在内建的eval函数工作中也是如此。

全局代码 | Global code

这类代码是在程序级别(level Program)中处理的,也就是说,在加载外部的js文件或局部的行内代码(在<script></script>标签之间)时。全局代码不包括任何在函数体内部的代码。

初始化时(程序开始时),ECStack像这样:

  1. ECStack = [
  2. globalContext
  3. ];

函数代码 | Function code

在进入函数代码时(所有类型的函数),新元素push到ECStack中。需要注意的是,某一个具体函数的代码不包括它的内部函数的代码。

例如,我们看一个递归一次的函数:

  1. (function foo(bar) {
  2. if(bar) {return;}
  3. foo(true);
  4. }) (false);

在这段代码执行时,ECStack的改变如下:

  1. //foo函数第一次激活时
  2. ECStrack = [
  3. <foo> functionContext
  4. globalContext
  5. ];
  6. // foo函数递归激活时
  7. ECStrack = [
  8. <foo> functionContext - recursively
  9. <foo> functionContext
  10. globalContext
  11. ];

每次离开当前执行上下文而从函数中返回时ECStack也据此pop一个层——连续的和从上到下的(译者按:先进后出)——就像栈的自然实现那样。当这个函数代码的工作结束时,ECStack再次回到只有globalContext的状态——直到程序结束。
一个抛出但未捕获的异常也可能退出一个或多个执行上下文:

  1. (function foo() {
  2. (function bar() {
  3. throw 'Exit from bar and foo context';
  4. }) ();
  5. }) ();

Eval代码 | Eval code

eval代码中的情况就更有趣了。这种情况下,有一个叫调用上下文(calling context)的概念——即被调用的eval函数所在的上下文。

eval函数的行为,比如变量或函数声明,实际上影响的是调用上下文:

  1. //影响全局上下文
  2. eval("var x = 10");
  3. (function foo() {
  4. //而这里的'y'是在foo函数的局部上下文中创建的
  5. eval("var y = 20");
  6. }) ();
  7. alert(x); // 10
  8. alert(y); // "undefined"

注意:在ES5的严格模式下,eval已经不再影响调用上下文,而是在一个局部沙盒(local sandbox)中评估相应的代码。

上面的例子中我们得到如下的ECStack变化:

  1. ECStack = [
  2. globalContext
  3. ];
  4. // eval('var x = 10');
  5. ECStack.push(
  6. evalContext,
  7. callingContext: globalContext
  8. );
  9. // eval exited context
  10. ECStack.pop();
  11. // foo funciton call
  12. ECStack.push(<foo> functionContext);
  13. // eval('var y = 20');
  14. ECStack.push(
  15. evalContext,
  16. callingContext: <foo> functionContext
  17. );
  18. // return from eval
  19. ECStack.pop();
  20. // return from foo
  21. ECStack.pop();

在旧版本(到1.9为止)的SpiderMonkey(Firefox的js引擎)中,允许以第二个参数的形式将一个调用上下文传入到eval函数中,因此,如果上下文还存在,它可以影响那些在(在函数中声明的)私有变量(private variables)。然而,由于安全方面的考虑现代引擎修复了它。

总结 | Conclusion

这篇中的概念是进一步分析与执行上下文相关的细节(例如变量对象variable object,作用域链scope chain)的基础,这些细节将在后面的章节中涉及到。

版权声明:本站文章除特别声明外,均采用署名-非商业性使用-禁止演绎 4.0 国际 许可协议,如需转载,请注明出处
  • ECMA-262-3 in detail——第七章:OOP(第二部分:ECMAScript实现)

    这一章的第二部分是关于EMCAScript中的面向对象编程。在第一部分中我们讨论了OOP的基本理论并勾画出和ECMAScript的相似之处。在阅读第二部分之前,如果有必要,我还是建议首先阅读这一章的第一部分.基本理论,因为后面将会用到其中的一些术语。

    发布:2015-05-26 阅读(1949)

  • ECMA-262-3 in detail——第七章:OOP(第一部分:一般理论)

    这一章我们讨论ECMAScript中面向对象编程(object-oriented programming)的几个主要方面。由于这一主题已经在许多文章中谈论过,本章并不打算“老调重弹”,而是试图更多地着眼于这些过程内在的理论方面。尤其是,我们将研究对象创建的算法,看看对象间的关系(包括最基本的关系——继承)是如何实现的,并且给出一些讨论中将用到的准确定义(我希望这样能够打消一些术语和思路上的疑惑以及一些关于Javascript文章中OOP部分的常见的混淆)。

    发布:2015-05-06 阅读(1707)

  • ECMA-262-3 in detail——第六章:闭包

    在这一章中我们来谈谈Javascript中被讨论最多的话题之一——关于闭包(closures)。事实上这个主题并不是新鲜的。然而我们在这里将试着更多从理论的角度去分析和理解它,然后我们还会看一下ECMAScript内关于闭包的内容。

    发布:2015-04-28 阅读(1716)

  • ECMA-262-3 in detail——第五章:函数

    在这章里我们讨论ECMAScript中的一个基本对象——函数。我们将会看到不同类型的函数如何影响一个上下文中的变量对象,以及这些函数的作用域链中都包含什么。我们将会回答像下面这样经常被问到的问题:“下面这两种创建函数的方式有什么区别吗(如果有的话,区别是什么呢)?”

    发布:2015-04-17 阅读(1855)

  • ECMA-262-3 in detail——第四章:作用域链

    正如我们从第二章.变量对象中了解到的,执行上下文的数据(变量,函数声明,函数形参)以变量对象的属性的方式储存。

    发布:2015-04-07 阅读(1650)

  • ECMA-262-3 in detail——第三章:this关键字

    许多程序员习惯于认为在编程语言中,this关键字是与面向对象编程紧密相关的,而且引用的是由构造式最新创建的对象。在ECMAScript中,这个概念也被实现了,然而我们将看到,在这里它不仅仅指向已创建的对象。

    发布:2015-03-25 阅读(1859)

  • ECMA-262-3 in detail——第二章:变量对象

    在程序中我们总是声明变量和函数然后用它们来搭建我们的系统。但是解释器(interpreter)是在哪里和以什么方式来找到我们的数据(函数,变量)的呢?

    发布:2015-03-24 阅读(1963)

  • ECMA-262-3 in detail——第一章:执行上下文

    第1章:在这一章里,我们将会讨论ECMAScript中的执行上下文(execution context)以及与它们相关的可执行代码(executable code)的类型。

    发布:2015-01-10 阅读(1909)