JavaScript内部道理系列-实行上下文(Execution Context)

提要

本文将向人人引见ECMAScript的实行上下文以及相干的可实行代码范例。

定义

每当控制器抵达ECMAScript可实行代码的时刻,控制器就进入了一个实行上下文。
实行上下文(简称:EC)是个笼统的观点,ECMA-262规范中用它来辨别差别范例的可实行代码。

规范中并没有从手艺完成的角度来定义实行上下文的详细组织和范例;这是完成规范的ECMAScript引擎所要斟酌的题目。

一系列运动的实行上下文从逻辑上构成一个栈。栈底老是全局上下文,栈顶是当前(运动的)实行上下文。当在差别的实行上下文间切换(退出的而进入新的实行上下文)的时刻,栈会被修正(经由过程压栈或许退栈的情势)。

可实行代码范例

可实行代码范例和实行上下文相干。有的时刻,当提到代码范例的时刻,实在就是在说实行上下文。

举个例子,我们将实行上下文的栈以数组的情势来示意:

ECStask = [ ];

每次控制器进入一个函数(哪怕该函数被递归挪用或许作为组织器),都邑发作压栈的操纵。内置eval函数事情的时刻也不破例。

全局代码

这类代码是在“顺序”级别上被处置惩罚的:比方,加载一个外部的js文件或许内联的js代码(被包含在<script></script>标签内)。全局代码不包含任何函数体内的代码。

在初始化的时刻(顺序最先),ECStack以下所示:

ECStack = [
    globalContext
];

函数代码

一旦控制器进入函数代码(各种函数),就会有新的元素会被压栈到ECStack。要注意的是:实体函数代码并不包含内部函数的代码。以下所示,我们挪用一个函数,该函数递归挪用本身一次:

(function foo(bar){
    if (bar){

    return;

}

foo(true);
})();

以后,ECStack就被修正成以下所示:

//起首激活foo函数
ECStack = [
     functionContext
    globalContext
];
//递归激活foo函数
ECStack = [
     functionContext - recursively
     functionContext
    globalContext
];

每次函数返回,退出当前运动的实行上下文时,ECStack就会被实行对应的退栈操纵——先进后出——和传统的栈完成一致。一样的,当抛出未捕捉的异常时,也会退出一个或许多个实行上下文,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

总结

这些基本理论关于背面实行上下文相干的细节(诸如变量对象、作用域链等等)剖析是异常必要的。

扩大浏览

ECMA-363-3规范文档的对应的章节—— 10. 实行上下文

via 前端翻译小站
赵静(goddyzhao)译自 Dmitry A.Soshnikov的文章Execution Context

    原文作者:kidsamong
    原文地址: https://segmentfault.com/a/1190000002446390
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞