重学JavaScript深刻理解系列(一)

JavaScript深刻理解——执行上下文(Execution Context)

定义

每当控制器到达ECMAScript可执行代码的时候,控制器就进入了一个执行上下文。 执行上下文(简称:EC) 之后出去要说EC由于够逼格😏 EC是个抽象的概念,ECMA-262标准中用它来区分不一样类型的可执行代码。数组

标准中并无从技术实现的角度来定义可执行上下文的具体结构和类型;这是现实标准的ECMAScript引擎所要考虑的问题。浏览器

一系列活动的执行上下文从逻辑上造成一个栈。栈底是全局上下文,栈顶是当前(活动的)执行上下文。当在不一样的执行上下文切换的时候,栈会被修改(经过压栈或者退栈的形式)。 bash

可执行代码类型

可执行代码类型和执行上下文相关。有的时候,当提到代码类型的时候,其实就是在说执行上下文。

举个🌰 咱们将执行上下文的栈以数组的形式来表示ecmascript

ECStask =[];
复制代码

每次控制器进入一个函数(哪怕该函数被递归调用或者做为构造器),都会发生压栈的操做。内置eval函数工做的时候也不例外 ide

全局代码

这类代码是在"程序"级别上被处理的:好比,加载一个外部的js文件或者内联的js代码(被包含在script标签内).全局代码不包含任何函数体内的代码。 在初始化的时候(程序开始的时候) ECStack以下
ECStask =[
    globalContext
];
复制代码

函数代码

一旦控制器进入函数代码(各种函数),就会有新的元素会被压栈到ECStack。

要注意的是:实体函数代码并不包括内部函数代码函数

以下所示,咱们调用一个函数,该函数递归调用本身一次:post

(function foo(bar){
      if(bar){
          return;
      }  
      foo(true);
    })();
复制代码

以后, ECStack就被修改为以下所示:ui

// 首先激活foo函数
ECStack = [
    functionContext
    globalContext
]

// 递归激活foo函数
ECStack = [
    functionContext - recursively
    functionContext 
    globalContext
]
复制代码

每次函数返回,退出当前活动的执行上下文时,ECStack就会被执行对应的退栈操做--(先进后出和传统的栈实现一致)。spa

一样的,当抛出未捕获的异常时,也会退出一个或者多个执行上下文,ECStack也会作相应的退栈操做。翻译

待这些代码完成以后,ECStack中就只剩下一个执行上下文(globalContext)直到整个程序结束。

Eval代码

说道Eval代码就比较有意思了。这里要提到一个叫作调用上下文的概念,好比:调用eval函数时候的上下文,就是一个调用上下文,eval函数中执行的动做(例如: 变量声明或者函数声明)会影响整个调用上下文:
eval('var x = 10');
(function foo(){
    eval('var y = 20');
})();
alert(x); //10
alert(y); // 'y' is not defined
复制代码

ECStack 会被修改成:

ECStack = [
    globalContext
]

// eval('var x = 10');
ECStack.push(
    evalContext,
    callingContext: globalContext
)

// eval exited context
ECStack.pop();

// foo function call
ECStack.push(functionContext);

// eval('var y = 20');
ECStack.push(
    evalContext,
    callingContext: functionContext
);

// return from eval
ECStack.pop();

// return from foo
ECStack.pop();
复制代码

在1.7以上版本SpiderMonkey的实现中(Firefox, Thunderbird浏览器内置的JS引擎),容许在调用eval函数的时候,将调用上下文做为的第二个参数传递给eval函数。所以,若是传入的调用上下文存在的话,就有可能会影响该上下文中原有的私有变量

function foo(){
    var x = 1;
    return function() {
        alert(x);
    }
}

var bar = foo();
bar(); // 1
eval('x = 2', bar); // 传递上下文,影响了内部变量var x
bar(); // 2
复制代码

原文地址
中文翻译版本

ps: 虽然都是别人翻译好的可是由于以为写的好仍是想敲一遍~也方便本身查阅

重学系列传送门

重学JavaScript深刻理解系列(二)
重学JavaScript深刻理解系列(三)
重学JavaScript深刻理解系列(四)
重学JavaScript深刻理解系列(五)
重学JavaScript深刻理解系列(六)

相关文章
相关标签/搜索