js之作用域与内存

81 阅读3分钟

执行上下文与作用域

执行上下文在js中是比较重要的概念,变量或函数的执行上下文决定了他们可以访问哪些数据。

每个上下文都有一个关联的变量对象,而这个上下文中定义的所有变量和函数都存在与这个对象中。虽然代码中无法访问到这个对象,但js内核会用到它。

  • 全局上下文是最外层的上下文,在浏览器中,全局上下文就是window对象,因此通过var定义的全局变量和函数都会成为window的属性和方法。
  • 每个函数调用都有自己的上下文。当代码执行进入函数时,函数的上下文被推到一个上下文栈上。在函数执行完之后,上下文栈会弹出该函数上下文,将控制权返还给之前的执行上下文。

作用域链

上下文中的代码在执行的时候,会创建变量对象的一个作用域链。

作用域链决定了各级上下文中的代码在访问变量和函数时的顺序。代码在执行的上下文变量对象始终位于作用域链的最前端。

全局上下文的变量对象始终时作用域链的最后一个变量对象。

垃圾回收

js是一种使用垃圾回收的语言,执行环境负责在代码执行时管理内存。

基本思路:确定哪个变量不会再使用,然后释放它占用的内存。这个过程是周期性的,即垃圾回收程序每隔一段时间就会自动执行。

垃圾回收程序必须跟踪记录哪个变量还会使用,以及哪个变量不会再使用,以便回收内存。

如何标记未使用的变量主要有两种实现方法:标记清理和引用计数。

  • 标记清理

    标记清理,当变量进入上下文,比如再函数内部声明一个变量时,这个变量会被加上存在于上下文中的标记。当变量离开上下文时,也会被加上离开上下文的标记。

    垃圾回收程序运行的时候,会标记内存中存储的所有变量。然而它会将所有在上下文中的变量,以及被在上下文中的变量引用的变量的标记去掉。在此之后再被加上标记的变量就是待删除的变量,原因时任何在上下文中的变量都访问不到他们了。随后垃圾回收程序做一次内存清理,销毁带标记的所有值并收回他们的内存。

  • 引用计数

    引用计数:对每个值都记录它被引用的次数。声明变量并给他赋予初始值的之后,引用次数为1.如果同一个值又被赋予给另一个变量,那么引用次数 + 1.当保存对该值的引用的变量被其他值覆盖了,那么应用次数-1.当一个值的引用次数为0时,可以收回其内存值。垃圾回收程序下次运行的时候就会释放引用次数为0 的数据。

内存泄漏

内存泄漏:由于不合理的引用,导致程序中不再使用的变量,无法被垃圾回收机制回收。

造成内存泄漏的原因:

  1. 意外声明全局变量
  2. 滥用闭包
  3. 脱离DOM的引用
  4. 被遗忘的定时器和回调函数