头图

再学JS高级笔记2:JavaScript的执行过程

2 JavaScript的执行过程

假如我们有下面一段代码,它在JavaScript中是如何被执行的 呢?

var name = "why"

function foo(){
    var name = "foo"
    console.log(name)
}

var num1 = 20
var num2 = 30
var result = num1 + num2
console.log(result) 

2.1 第一步:初始化全局对象

image-20230321205135620.png

JS引擎会在执行代码之前,在堆内存中创建一个全局对象:Global Object(GO)

  • 该对象所有的作用域(scope)都可以访问
  • 里面会包含DateArrayStringNumbersetTimeoutsetInterval等等
  • 其中还要一个window属性指向自己

    创建GO的伪代码
    var GlobalObject = {
        String: '类',
        Date: '类',
        window: GlobalObject,
        name: undefined,
        num1: undefined,
        num2: undefined,
        result: undefined,
        foo: 0xa00//会指向专门为该函数在内存开辟一个空间地址
    }
  • 开辟的函数空间存储的内容和结构如下:
    image-20230323155558076.png

2.2 第二步:执行调用栈

代码要想运行,都需要先添加到内存里面,内存里面划分为栈结构和堆结构
image-20211121155153131.png

  1. JS引擎为了执行代码,内部有一个执行上下文(Execution Context Stack, ECS) 。那么现在它要执行谁呢?执行的是全局的代码块(可以理解为函数)。
  2. 为了全局代码也能够正常执行,需要创建 全局执行上下文(Global Execution Context (GEC))
  3. GEC会放入到ECS中执行,里面包含两部分内容:
    image-20211123195115651.png
  • 第一部分:在代码执行前,在parser转成AST的过程中,会将全局定义的变量、哈描述等加入到GlobalObject中,但是并不会赋值

    • 这个过程也称之为变量的作用域提升(hoisting)

      var name = "why"
      
      function foo(){
          var name = "foo"
          console.log(name)
      }
      console.log(num1) //假如在这里加入这行代码,打印的num1值为undefined,因为已经在go里面声明
      var num1 = 20
      var num2 = 30
      var result = num1 + num2
      console.log(result) 
    • 全局执行上下文GEC中的VO(variable Object)就是GO(Global Object)对象
  • 第二部分:开始执行代码执行,对变量赋值,或者执行其他的函数
    image-20211123195617728.png

2.3 遇到函数如何执行

在执行的过程中执行到一个函数时,就会根据函数体创建一个函数执行上下文(Functional Execution Context,简称FEC),并且压入到ECStack中。
image-20211123200639178.png

FEC中包括三部分内容:

  • 第一部分:在解析函数成 为AST树结构时,会创建一个Activation Object(AO);

    • AO中包括形参、arguments、函数定义和指向函数对象、定义的变量
  • 第二部分:作用域链,由VO(在函数中就是AO对象)和父级(parent scope)VO组成,查找时会一层层查找

    • 当我们查找一个变量时,真实的查找路径是沿着作用域链来查找的
  • 第三部分:this绑定的值 (this的绑定规则后续再深究)
    image-20211123200256204.png

2.4 FEC执行代码

var name = "why"

foo(123)
function foo(num) {
    console.log(m)
    var m = 10
    var n = 2o
    console.log("foo")
}
  1. 编译阶段:创建全局的GO,并在GO内部定义变量,变量值为undefined
    image-20230330214302307.png
  2. 编译阶段:为foo函数开辟内存,并将GO内的foo指向该地址
    image-20230330214910261.png
  3. 执行阶段:执行var name ="why",为name赋值
    image-20230330215045446.png
  4. 执行阶段:执行foo()

    • 为foo创建一个FEC并放入ECStask中
      image-20230330215436982.png
    • 真正开始执行foo中的代码
      image-20230330221237113.png
    • 当foo执行完后foo的FEC出栈
      image-20230330221421186.png

2.5 变量环境和记录

前面的讲解都是基于早期ECMA的版本规范
image-20211123200934769.png
在最新的ECMA的版本规范中,对一些词汇进行了修改
image-20211123201450699.png
通过上面的变化我们可以知道在最 新的ECMA标准中,我们前面的变量对象VO已经有另一个称呼(变量环境,VE)了。

大胆求证 小心验证

3 声望
0 粉丝
0 条评论
推荐阅读
「多图预警」完美实现一个@功能
一天产品大大向 boss 汇报完研发成果和产品业绩产出,若有所思的走出来,劲直向我走过来,嘴角微微上扬。产品大大:boss 对我们的研发成果挺满意的,balabala...(内心 OS:不听,讲重点)产品大大:咱们的客服 I...

wuwhs39阅读 4.7k评论 5

封面图
安全地在前后端之间传输数据 - 「3」真的安全吗?
在「2」注册和登录示例中,我们通过非对称加密算法实现了浏览器和 Web 服务器之间的安全传输。看起来一切都很美好,但是危险就在哪里,有些人发现了,有些人嗅到了,更多人却浑然不知。就像是给门上了把好锁,还...

边城31阅读 7.1k评论 5

封面图
涨姿势了,有意思的气泡 Loading 效果
今日,群友提问,如何实现这么一个 Loading 效果:这个确实有点意思,但是这是 CSS 能够完成的?没错,这个效果中的核心气泡效果,其实借助 CSS 中的滤镜,能够比较轻松的实现,就是所需的元素可能多点。参考我们...

chokcoco19阅读 2k评论 2

在前端使用 JS 进行分类汇总
最近遇到一些同学在问 JS 中进行数据统计的问题。虽然数据统计一般会在数据库中进行,但是后端遇到需要使用程序来进行统计的情况也非常多。.NET 就为了对内存数据和数据库数据进行统一地数据处理,发明了 LINQ (L...

边城17阅读 1.9k

封面图
【已结束】SegmentFault 思否写作挑战赛!
SegmentFault 思否写作挑战赛 是思否社区新上线的系列社区活动在 2 月 8 日 正式面向社区所有用户开启;挑战赛中包含多个可供作者选择的热门技术方向,根据挑战难度分为多个等级,快来参与挑战,向更好的自己前进!

SegmentFault思否20阅读 5.6k评论 10

封面图
过滤/筛选树节点
又是树,是我跟树杠上了吗?—— 不,是树的问题太多了!🔗 相关文章推荐:使用递归遍历并转换树形数据(以 TypeScript 为例)从列表生成树 (JavaScript/TypeScript) 过滤和筛选是一个意思,都是 filter。对于列表来...

边城18阅读 7.6k评论 3

封面图
Vue2 导出excel
2020-07-15更新 excel导出安装 {代码...} src文件夹下新建一个libs文件夹,新建一个excel.js {代码...} vue页面中使用 {代码...} ===========================以下为早期的文章今天在开发的过程中需要做一个Vue的...

原谅我一生不羁放歌搞文艺14阅读 19.8k评论 9

大胆求证 小心验证

3 声望
0 粉丝
宣传栏