前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入理解JavaScript 执行上下文

深入理解JavaScript 执行上下文

作者头像
木子星兮
发布2020-07-16 15:47:21
3480
发布2020-07-16 15:47:21
举报
文章被收录于专栏:前端小码农前端小码农

只有理解了执行上下文,才能更好地理解 JavaScript 语言本身,比如变量提升,作用域,闭包等

执行上下文

执行上下文是当前代码的执行环境。

执行上下文主要是三种类型:

  1. 全局执行上下文:全局执行环境是最外围的一个执行环境,在浏览器的全局对象是 window, this指向这个对象
  2. 函数执行上下文:可以有无数个,函数被调用的时候会被创建。每次调用函数都会创建一个新的执行上下文。
  3. eval执行上下文,很少用。

每个执行上下文,都有三个重要属性:

  1. 变量对象 (variable object, VO): 每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。

在函数上下文中,使用活动对象 (activation object, AO) 来表示变量对象。活动对象和变量对象其实是一个东西,只有当进入一个执行环境时,这个执行上下文的变量对象才会被激活,此时称为 活动对象(AO),只有活动对象上的属性才能被访问。

  1. 作用域链(scope chain):当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。
  2. this

执行上下文的生命周期:创建 -> 执行 -> 回收

1. 创建阶段:
1.1 创建变量对象:
  • 初始化函数的参数 arguments
  • 函数声明
  • 变量声明

举个简单的例子来理解变量对象

代码语言:javascript
复制
function getName(name) {
    var b = 2;
    function foo() {};
    var bar = function() {};

}
getName('lucystar')

此时的 AO 大致如下

代码语言:javascript
复制
AO = {
    arguments: {
        0: 'lucystar',
        length: 1
    },
    name: 'lucystar',
    b: undefined,
    foo: reference to function foo(){},
    bar: undefined
}

上面例子中涉及到了变量提升和函数提升,之前在 从JS底层理解var、let、const这边文章中也介绍过

1.2 创建作用域链

函数的作用域在函数定义的时候就确定了。作用域链本身包含变量对象,当查找变量时,会先从当前上下文中的变量对象中查找,如果没有找到,就会从父级执行上下文的变量对象中查找,一直找到全局执行上下文的变量对象

1.3 确定this的指向

这部分又分为多种情况,具体的可以查看另一篇文章 一文理解this&call&apply&bind

2. 执行阶段

执行变量赋值,代码执行

3. 回收阶段

执行上下文出栈被垃圾回收机制进行回收。关于内存回收的内容,可以查看 V8内存管理及垃圾回收机制

执行上下文栈

执行上下文栈是用来管理执行上下文的。在执行上下文创建好后,JavaScript引擎会将执行上下文压入到栈中,通常把这种用来管理执行上下文的栈称为执行上下文栈,又称调用栈。

代码语言:javascript
复制
let a = 'javascript';

function foo() {
    console.log('foo');
    bar();
}
function bar() {
    console.log('bar');
}
foo();

执行上下文栈

  1. 上述代码在浏览器加载时,JavaScript 引擎创建了一个全局执行上下文并把它压入到当前执行栈。
  2. 当遇到 foo() 函数调用时, JavaScript 引擎创建了一个 foo 函数执行上下文并把它压入到当前执行栈的顶部。
  3. 当从 foo() 函数内部调用 bar() 函数时,JavaScript 引擎创建了一个 bar 函数执行上下文并把它压入到当前执行栈的顶部。
  4. 当函数 bar 执行完毕,它的执行上下文会从当前栈中弹出,控制流程到达下一个执行上下文,即 foo() 函数的执行上下文。
  5. 当 foo() 执行完成,它的执行上下文从栈弹出,控制流程到达全局执行上下文,一旦所有代码执行完成,javaScript 引擎就从当前栈中移除全局执行上下文。

为什么基本数据类型存储在栈中,引用数据类型存储在堆中?JavaScript引擎需要用栈来维护程序执行期间的上下文的状态,如果栈空间大了的话,所有数据都存放在栈空间里面,会影响到上下文切换的效率,进而影响整个程序的执行效率。

参考

  • JavaScript深入之执行上下文栈[1]
  • JavaScript深入之执行上下文[2]
  • JavaScript深入之变量对象[3]
  • 深入理解JavaScript系列(11):执行上下文(Execution Contexts)[4]
  • 《JavaScript高级程序设计 (第三版)》

参考资料

[1]

JavaScript深入之执行上下文栈: https://github.com/mqyqingfeng/Blog/issues/4

[2]

JavaScript深入之执行上下文: https://github.com/mqyqingfeng/Blog/issues/8

[3]

JavaScript深入之变量对象: https://github.com/mqyqingfeng/Blog/issues/5

[4]

深入理解JavaScript系列(11):执行上下文(Execution Contexts): https://www.cnblogs.com/TomXu/archive/2012/01/13/2308101.html

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-07-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 牧码的星星 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 执行上下文
    • 执行上下文主要是三种类型:
      • 每个执行上下文,都有三个重要属性:
        • 执行上下文的生命周期:创建 -> 执行 -> 回收
          • 1. 创建阶段:
          • 2. 执行阶段
          • 3. 回收阶段
      • 执行上下文栈
      • 参考
        • 参考资料
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档