开幕
作为一名 JavaScript 程序开发人员,如果被问及 JavaScript 代码的执行顺序,你脑海中是否有一个直观的印象——JavaScript 是按顺序执行的javascript上下文,但事实真的是这样吗?
我们先来看两个小例子:
<code class="js">var foo = function () { console.log('foo1'); } foo(); // foo1 var foo = function () { console.log('foo2'); } foo(); // foo2
function foo() {
console.log('foo1');
}
foo(); // foo2
function foo() {
console.log('foo2');
}
foo(); // foo2
研究过笔试题的人都知道:
JavaScript引擎并不是逐行分析执行程序,而是一段一段地分析执行。 当一段代码被执行时,它会执行一个规划任务。
比如我们熟悉的JavaScript中的变量优化,比如函数优化,都是在这个规划阶段完成的。
这篇文章我们就来深入看看这一段中的段落是如何定义的?
JavaScript引擎遇到什么样的代码可以做“准备工作”呢? 为了回答这个问题我们引入一个概念——执行上下文。
执行上下文
如果你中学做过阅读理解,一定见过这样一个题目:结合上下文解读句子。 这里的上下文是指该短语所在的段落,或者该短语所在段落的相邻段落。 事实上,这里描述的是一个语句的上下文和范围。 类比程序,我们可以做出如下定义:
执行上下文是当前JavaScript代码被解析和执行的环境的具体概念。执行上下文的类型
执行上下文分为三种类型,有时也称为可执行代码(executable code)
例如,当执行一个函数时,就会进行准备工作。 这里的“准备工作”,我们用一个更专业的术语,叫做“执行上下文(execution context)”。
执行栈
下一个问题来了。 我们写了太多的函数。 如何管理创建的这么多执行上下文? 于是JavaScript引擎创建了一个执行上下文栈(Execution context stack)ECStack来管理执行上下文。
这里我们可以简单的把ECStack看成一个字段javascript上下文,类似这样:
ECStack = [];
执行堆栈也称为调用堆栈,具有 LIFO(后进先出)结构,用于存储代码执行过程中创建的所有执行上下文。
我们来看一段代码来理解这个过程:
var a = 'Hello World!';
function first() {
console.log('Inside first function');
second();
console.log('Again inside first function');
}
function second() {
console.log('Inside second function');
}
first();
console.log('Inside Global Execution Context');
// Inside first function
// Inside second function
// Again inside first function
// Inside Global Execution Context
下图可以更清楚的说明之前的执行过程。
看两个思考题
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f();
}
checkscope();
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f;
}
checkscope()();
两段代码的结果是一样的,但是这两段代码有什么区别呢?
答案是执行上下文堆栈变化不同。
我们来模拟一下第一段代码:
ECStack.push( functionContext);
ECStack.push( functionContext);
ECStack.pop();
ECStack.pop();
我们来模拟一下第二段代码:
ECStack.push( functionContext);
ECStack.pop();
ECStack.push( functionContext);
ECStack.pop();
为了更详细地解释两个函数执行的差异,我们需要探究执行上下文包含哪些内容,并且需要对变量对象的相关内容有更深入的了解。
参考链接:
《理解 JavaScript 中的执行上下文和执行堆栈》
《JavaScript深入执行上下文栈》