详解JavaScript中的执行上下文及调用堆栈


Posted in Javascript onApril 29, 2021

一、执行上下文是什么

代码运行是在一定的环境之中运行的,这个运行环境我们就成为执行环境,也就是执行上下文,按照执行环境不同,我们可以分为三类:

全局执行环境:代码首次执行时候的默认环境

函数执行环境:每当执行流程进入到一个函数体内部的时候

Eval执行环境:当eval函数内部的文本执行的时候

二、执行上下文栈是什么

既然是‘栈',那就得符合‘栈'的特性,即数据结构是先进后出。下面我们看一段代码:

function cat(a){
    if(a<0){
        return false;
    }
    console.log('入栈:'+a);
    cat(a-1);
    console.log('出栈:'+a);
}
cat(3);
// 入栈:3
// 入栈:2
// 入栈:1
// 入栈:0
// 出栈:0
// 出栈:1
// 出栈:2
// 出栈:3

我们来分析上面的代码的执行过程:

①浏览器加载时,程序进入全局执行上下文,将其压入一个栈内(第一个进入的,所以最底层);该执行上下文下只有一个函数cat、cat调用、参数3;

②程序进入cat函数内,即进入该函数执行上下文,也将其压入栈内(第二个进入的,所以倒数第二层),因为参数为3大于0,继续往下执行,输出'入栈:3';

③程序继续执行,调用函数cat,再次进入新的函数执行上下文,继续压入栈内(第三个进入,倒数第三层),参数为a-1,循环②步骤;这里,需要注意的是,因为调用了函数cat(a-1),导致下一行代码'出栈:a'(此时a仍为3),也就是'出栈:3'暂时搁浅起来,存在栈内倒数第二层

④不断重复②③步骤,以次输出'入栈:2'、'入栈:1'、'入栈:0';同时被搁浅的有'出栈:2'(栈内倒数第三层)、'出栈:1(栈内倒数第四层)'、'出栈:0(栈内倒数第五层)';

⑤按照栈的特性,被搁浅起来的4个输出项:以次输出'入栈:3'、'入栈:2'、'入栈:1'、'入栈:0';
以上就是执行上下文栈的具体情况,请大家手动代码练习一下,相信会容易理解透彻。

详解JavaScript中的执行上下文及调用堆栈

三、执行上下文栈的过程细节

我们已经知道,每次调用函数都会执行一个新的上下文,每个执行上下文都分为两个阶段:创建阶段、执行阶段
创建阶段:指的是程序调用函数,但代码未执行时的阶段;
执行阶段:指的是变量分配、函数执行等代码执行阶段;

(一)创建阶段

该阶段会调用函数数时,创建一个执行上下文对象(executionContextObj),该对象又包含了三个对象,分别是作用域链对象(scopeChain)、变量对象(variableObject,简称VO)、this对象,其中VO包括变量声明(variable)、函数声明(function)、参数(arguments)等。
这三个对象分别是在三个步骤创建的:
步骤1:初始化作用域链(scopeChain),开辟栈内存

步骤2:创建参数、函数、变量

步骤3:决定上下文的'this'的值

结合代码来进一步分析一下上面的步骤:

function cat(name) {
    var a = '年年';
    var b = function () {};
    this.name = name;
    function c() {
        console.log(this.name);
    }
    c();
}
cat('有鱼');

这段代码在调用函数 cat('有鱼')时,执行上下文是处于 创建阶段的,代码解析为:

cat执行上下文对象 = {
    scopeChain: { ... },// 1.创建作用域链,开辟栈内存
    variableObject: { 2.创建变量对象
        arguments: {  // 2.1 解析参数
            0: '有鱼',
            length: 1
        },
        name: '有鱼',  // 2.1 解析参数,创建形参名称,并进行参数赋值
        c: function c()  // 2.2 找到函数声明c,并将c作为属性,function c作为值
        a: undefined,  // 2.3 找到变量声明a,初始化为undefined,该阶段只看声明部分,不进行赋值
        b: undefined   // 2.3 找到变量声明b,初始化为undefined,该阶段只看声明部分,不进行赋值
    },
    this: {  3.创建this对象
        this:cat('有鱼') // 3.1 指向此次调用的对象
        name:undefined // 3.2 对象属性name的初始化为undefined
    };
    c() //又进入函数c执行上下文,跟cat函数一样,暂不展开 
}

通过代码解析我们可以得出以下结论

①三个步骤顺序不能乱
②VO步骤内,先执行函数声明,再执行变量声明
③只有参数可以在此阶段进行赋值,变量、函数都只能声明

详解JavaScript中的执行上下文及调用堆栈

(二)执行阶段

该阶段js解释器执行上下文中的函数代码,逐行运行js代码,并给变量赋值;
还是结合代码来分析:

cat执行上下文对象 = {
    scopeChain: { ... },
    variableObject: { 
        arguments: { 
            0: '有鱼',
            length: 1
        },
        name: '有鱼', 
        c: function c(),
        a: '年年',  // 变量a进行赋值
        b: function b   // 变量b进行赋值
    },
    this: {  3.创建this对象
        this:cat('有鱼') 
        name:'有鱼' // 对象属性name进行赋值
    }
}

以上就是详解JavaScript中的执行上下文及调用堆栈的详细内容,更多关于JavaScript中的执行上下文及调用堆栈的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
JS常用正则表达式总结
Nov 12 Javascript
js简单正则验证汉字英文及下划线的方法
Nov 28 Javascript
微信小程序 两种为对象属性赋值的方式详解
Feb 23 Javascript
ES6新特性之字符串的扩展实例分析
Apr 01 Javascript
为JQuery EasyUI 表单组件增加焦点切换功能的方法
Apr 13 jQuery
浅谈Node.js 中间件模式
Jun 12 Javascript
Vue点击切换颜色的方法
Sep 13 Javascript
Node.JS用纯JavaScript生成图片或滑块式验证码功能
Sep 12 Javascript
layui 实现二级弹窗弹出之后 关闭一级弹窗的方法
Sep 18 Javascript
Element Dropdown下拉菜单的使用方法
Jul 26 Javascript
在vue中嵌入外部网站的实现
Nov 13 Javascript
html中创建并调用vue组件的几种方法汇总
Nov 17 Javascript
JavaScript实现淘宝商品图切换效果
JavaScript实现显示和隐藏图片
Apr 29 #Javascript
JS Canvas接口和动画效果大全
Apr 29 #Javascript
JS ES6异步解决方案
Apr 29 #Javascript
聊聊JS ES6中的解构
Apr 29 #Javascript
详解TypeScript中的类型保护
Apr 29 #Javascript
7个你应该知道的JS原生错误类型
Apr 29 #Javascript
You might like
PHP中如何调用webservice的实例参考
2013/04/25 PHP
PHP获取指定函数定义在哪个文件中以及其所在的行号实例
2014/05/08 PHP
PHP高级编程实例:编写守护进程
2014/09/02 PHP
JavaScript 用cloneNode方法克隆节点的代码
2012/10/15 Javascript
解决ExtJS在chrome或火狐中正常显示在ie中不显示的浏览器兼容问题
2013/01/11 Javascript
js open() 与showModalDialog()方法使用介绍
2013/09/10 Javascript
jquery实现带缩略图的全屏图片画廊效果实例
2015/06/25 Javascript
老生常谈JavaScript数组的用法
2016/06/10 Javascript
Angularjs中三种数据的绑定策略(“@”,“=”,“&amp;”)
2016/12/23 Javascript
详细AngularJs4的图片剪裁组件的实例
2017/07/12 Javascript
vue 监听键盘回车事件详解 @keyup.enter || @keyup.enter.native
2018/08/25 Javascript
详解如何解决vue开发请求数据跨域的问题(基于浏览器的配置解决)
2018/11/12 Javascript
JS实现数据动态渲染的竖向步骤条
2020/06/24 Javascript
详解JavaScript之Array.reduce源码解读
2020/11/01 Javascript
[02:22]《新闻直播间》2017年08月14日
2017/08/15 DOTA
Python中实现远程调用(RPC、RMI)简单例子
2014/04/28 Python
使用Python的Twisted框架编写简单的网络客户端
2015/04/16 Python
利用Python3分析sitemap.xml并抓取导出全站链接详解
2017/07/04 Python
Django1.9 加载通过ImageField上传的图片方法
2018/05/25 Python
Python实现网站表单提交和模板
2019/01/15 Python
Python判断两个文件是否相同与两个文本进行相同项筛选的方法
2019/03/01 Python
Python 实现交换矩阵的行示例
2019/06/26 Python
Tensorflow tf.nn.atrous_conv2d如何实现空洞卷积的
2020/04/20 Python
python的reverse函数翻转结果为None的问题
2020/05/11 Python
德国自行车商店:Tretwerk
2019/06/21 全球购物
俄罗斯最大的在线手表商店:Bestwatch.ru
2020/01/11 全球购物
Vilebrequin美国官方网上商店:法国豪华泳装品牌
2020/02/22 全球购物
斯洛伐克最大的婴儿食品和用品网上商店:Feedo.sk
2020/12/21 全球购物
春游踏青活动方案
2014/08/14 职场文书
签证扫盲贴,41个常见签证知识,需要的拿走
2019/08/09 职场文书
HTML中的表单Form实现居中效果
2021/05/25 HTML / CSS
MySQL Router实现MySQL的读写分离的方法
2021/05/27 MySQL
Python实现socket库网络通信套接字
2021/06/04 Python
python 爬取哔哩哔哩up主信息和投稿视频
2021/06/07 Python
Java实现多文件上传功能
2021/06/30 Java/Android
阿里云国际版 使用Nginx作为HTTPS转发代理服务器
2022/05/11 Servers