每当控制器到达ECMAScript可执行代码的时候,控制器就进入了一个执行上下文。 执行上下文(简称:EC) 之后出去要说EC由于够逼格😏 EC是个抽象的概念,ECMA-262标准中用它来区分不一样类型的可执行代码。数组
标准中并无从技术实现的角度来定义可执行上下文的具体结构和类型;这是现实标准的ECMAScript引擎所要考虑的问题。浏览器
一系列活动的执行上下文从逻辑上造成一个栈。栈底是全局上下文,栈顶是当前(活动的)执行上下文。当在不一样的执行上下文切换的时候,栈会被修改(经过压栈或者退栈的形式)。 bash
举个🌰 咱们将执行上下文的栈以数组的形式来表示ecmascript
ECStask =[];
复制代码
每次控制器进入一个函数(哪怕该函数被递归调用或者做为构造器),都会发生压栈的操做。内置eval函数工做的时候也不例外 ide
ECStask =[
globalContext
];
复制代码
要注意的是:实体函数代码并不包括内部函数代码。函数
以下所示,咱们调用一个函数,该函数递归调用本身一次: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('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深刻理解系列(六)