JavaScript内存管理和闭包

JavaScript执行原理

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

1. 首先会初始化全局对象

js引擎会在执行代码之前,会在堆内存中创建一个全局对象:Global Object(GO),对于浏览器环境就是window,对于node环境中的全局变量为global,类似浏览器中的window ,但不推荐在代码中使用,还有process对象,提供了当前Node.js进程相关信息和控制方法。
* 该对象内 所有的作用域(scope)都可以访问该对象上的内容;
* 里面会包含Date、Array、String、Number、setTimeout、setInterval等等;
* 其中还有一个window属性指向自己

在这里插入图片描述

2. 为每个作用域块创建执行上下文并放入执行上下文栈中

js引擎内部有一个执行上下文栈(Execution Context Stack,简称ECS),它是用于执行代码的调用栈。
那么现在它要执行谁呢?执行的是全局的代码块:
在这里插入图片描述
其中,this为当前上下文的引用。

  • 全局的代码块为了执行会构建一个执行上下文 Global Execution Context(GEC),函数代码块会创建执行上下文、全局代码块也会创建执行上下文,es6后块级作用域也会创建执行上下文,只有创建了执行上下文,才会被放入到执行上下文栈中,然后执行代码;
  • 执行上下文会被放入到执行上下文栈中 执行;
    执行上下文被放入到执行上下文栈中的内容会包含两部分:
    • 第一部分:在代码执行前,在parser转成AST的过程中,会将全局定义的变量、函数等加入到GlobalObject中。这个过程也称之为变量的作用域提升(hoisting) 。注意函数声明既提升又赋值且优先级比较var声明的变量还高,而var声明的变量只提升,不赋值。
      在这里插入图片描述
      其中,foo打印内容为字符串abc。

    • 第二部分:在代码执行中,创建执行上下文,对变量赋值,或者执行其他的函数;

JavaScript执行原理总结

参考链接:执行过程中上下文栈的变动演示
1. 初始化全局对象
2. 对编写的代码进行parse,parse过程中var变量和声明式函数该提升的提升。
3. 执行代码,执行过程中如遇到函数调用,对函数进行创建上下文,并放入上下文栈中,且每一个执行上下文会关联一个VO(Variable Object,变量对象),变量和函数声明会被添加到这个VO对象中。

注意:如果函数是多层函数嵌套,初始化时候只解释第一层,当执行的时候如果碰到里面还有函数,则再解释,然后再执行。 -> JavaScript是一种解释型语言,它边解释边执行代码。当浏览器加载JavaScript代码时,它会逐行解释代码并立即执行。这与编译型语言(如C++)不同,编译型语言需要在程序运行之前将代码编译成机器语言。

补充资料1:认识VO对象(Variable Object)
在这里插入图片描述
补充资料2:VO、GO(global obejct)、AO(activation object)
在这里插入图片描述

参考链接:链接

作用域链

作用域链其实是被保存在函数中的,是在代码定义的时候就被确定了,和函数执行无关,因此寻找变量只需要看代码编写顺序,和什么时候执行无关。

小技巧:当打断点的时候可以看到当前debug这一行的Scope内容。
在这里插入图片描述


内存管理

不管什么样的编程语言,在代码的执行过程中都是需要给它分配内存的,不同的是某些编程语言需要我们自己手动的管理内存,某些编程语言会可以自动帮助我们管理内存。

不管以什么样的方式来管理内存,内存的管理都会有如下的生命周期:

  • 第一步:分配申请你需要的内存(申请);
  • 第二步:使用分配的内存(存放一些东西,比如对象等);
  • 第三步:不需要使用时,对其进行释放;

常见的GC算法:

参考链接:链接

  1. 引用计数
  2. 标记清除(可达性算法) -目前应用最多,V8也用这个
    在这里插入图片描述

通过设置为null来删除引用关系

闭包

参考链接:闭包

在计算机科学中对闭包的定义,闭包其实就是一种结构体,由一个函数和一个关联的环境组成的东西。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/yexudengzhidao/article/details/131865834
今日推荐