资讯专栏INFORMATION COLUMN

深入学习js之——执行上下文栈

Lucky_Boy / 2892人阅读

摘要:当遇到函数调用时,引擎为该函数创建一个新的执行上下文并把它压入当前执行栈的顶部。参考链接理解中的执行上下文和执行栈深入之执行上下文栈

开篇

作为一个JavaScript的程序开发者,如果被问到JavaScript代码的执行顺序,你脑海中是不是有一个直观的印象 -- JavaScript 是顺序执行的,可事实真的是这样的吗?

让我们首先看两个小例子:

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)

全局执行上下文: 只有一个,浏览器中的全局对象就是window对象,this指向这个全局对象。

函数执行上下文: 存在无数个,只有在函数被调用的时候才会被创建,每次调用函数都会创建一个新的执行上下文。

Eval 函数执行上下文: 指的是运行在eval函数中的代码,很少用而且不建议使用。

举个例子,当执行到一个函数的时候,就会进行准备工作,这里的"准备工作",让我们用个更专业一点的说法,就叫做"执行上下文(execution context)"。

执行栈

接下来问题来了,我们写的函数多了去了,如何管理创建的那么多执行上下文呢?所以 JavaScript 引擎创建了执行上下文栈(Execution context stack )ECStack 来管理执行上下文。

这里我们可以简单的认为 ECStack 是一个数组,类似这样:

ECStack = [];

执行栈,也叫做调用栈,具有 LIFO(last in first out 后进先出) 结构,用于存储在代码执行期间创建的所有执行上下文。

首次运行JavaScript代码的时候,会创建一个全局执行的上下文并Push到当前的执行栈中,每当发生函数调用,引擎都会为该函数创建一个新的函数执行上下文并Push当前执行栈的栈顶。

当栈顶的函数运行完成后,其对应的函数执行上下文将会从执行栈中Pop出,上下文的控制权将移动到当前执行栈的下一个执行上下文。

让我们看一段代码来理解这个过程:

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

当上述代码在浏览器加载时,JavaScript引擎创建了一个全局执行上下文并把它压入(push) 当前的执行栈。当遇到 first() 函数调用时,JavaScript引擎为该函数创建一个新的执行上下文并把它压入当前执行栈的顶部

当从 first() 函数内部调用 second() 函数时,JavaScript引擎为 second() 函数创建了一个新的执行上下文并把它压入当前执行栈的顶部,当 second() 函数执行完毕,它的执行上下文会从当前栈弹出(pop),并且控制流程到达下一个执行上下文,即 first() 函数的执行上下文。

first() 执行完毕,它的执行上下文从栈中弹出,控制流程到达了全局执行上下文。一旦所有的代码执行完毕,JavaScript引擎从当前栈中移出全局执行上下文。

下面这张图,能够更加清晰的解释上面这个执行过程

看两个思考题
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深入之执行上下文栈》

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/101738.html

相关文章

  • 深入学习js——执行下文

    摘要:思考题在深入学习之词法作用域和动态作用域中,提出这样一道思考题思考题一思考题二两段代码都会打印但是还是有些许差异的,本文就详细的解析执行上下文栈和执行上下文的具体变化过程。 在《深入学习js之——执行上下文栈》中说过,当JavaScript代码执行一段可执行代码(executable code)时,会创建对应的执行上下文(execution context) 对于每一个执行上下文,都有...

    baukh789 评论0 收藏0
  • 深入学习js——作用域链

    摘要:开篇作用域是每种计算机语言最重要的基础之一,因此要想深入的学习作用域和作用域链就是个绕不开的话题。这样由多个执行上下文的变量对象构成的链表就叫做作用域链。这时候执行上下文的作用域链,我们命名为至此,作用域链创建完毕。 开篇 作用域是每种计算机语言最重要的基础之一,因此要想深入的学习JavaScript,作用域和作用域链就是个绕不开的话题。 在《深入学习js之—-执行上下文栈》中我们提到...

    lemanli 评论0 收藏0
  • 【进阶1-2期】JavaScript深入执行下文和变量对象

    摘要:本计划一共期,每期重点攻克一个面试重难点,如果你还不了解本进阶计划,点击查看前端进阶的破冰之旅本期推荐文章深入之执行上下文栈和深入之变量对象,由于微信不能访问外链,点击阅读原文就可以啦。 (关注福利,关注本公众号回复[资料]领取优质前端视频,包括Vue、React、Node源码和实战、面试指导) 本周正式开始前端进阶的第一期,本周的主题是调用堆栈,今天是第二天。 本计划一共28期,每期...

    Richard_Gao 评论0 收藏0
  • JavaScript深入系列15篇正式完结!

    摘要:写在前面深入系列共计篇已经正式完结,这是一个旨在帮助大家,其实也是帮助自己捋顺底层知识的系列。深入系列自月日发布第一篇文章,到月日发布最后一篇,感谢各位朋友的收藏点赞,鼓励指正。 写在前面 JavaScript 深入系列共计 15 篇已经正式完结,这是一个旨在帮助大家,其实也是帮助自己捋顺 JavaScript 底层知识的系列。重点讲解了如原型、作用域、执行上下文、变量对象、this、...

    fxp 评论0 收藏0
  • JavaScript深入执行下文

    摘要:深入系列第七篇,结合之前所讲的四篇文章,以权威指南的为例,具体讲解当函数执行的时候,执行上下文栈变量对象作用域链是如何变化的。前言在深入之执行上下文栈中讲到,当代码执行一段可执行代码时,会创建对应的执行上下文。 JavaScript深入系列第七篇,结合之前所讲的四篇文章,以权威指南的demo为例,具体讲解当函数执行的时候,执行上下文栈、变量对象、作用域链是如何变化的。 前言 在《Jav...

    gougoujiang 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<