JavaScript进阶-垃圾回收机制和闭包

本章的主要内容为JavaScript中两个重要的概念:垃圾回收机制和闭包。

垃圾回收机制

内存基础知识

在开始介绍垃圾回收机制之前,我们需要先了解一下编程语言中内存的一些基本知识。

内存的生命周期
一般程序中的内存生命周期分为三个阶段:分配内存、使用内存和释放内存。
全局变量和局部变量都会在内存中分配空间,全局变量在程序运行期间一直存在,而局部变量在不再使用之后就会被释放。
内存泄漏
内存泄漏是指程序中已经分配的内存由于某种原因没有被释放或者无法释放,导致内存空间被占用,从而影响程序的性能和稳定性。

什么是垃圾回收机制?

垃圾回收机制常见于现代高级语言,如Java、C#、JavaScript等,它的主要作用是自动释放不再使用的内存空间,防止内存泄漏。
垃圾回收机制主要依赖于垃圾回收算法进行工作,下面是几种常见的垃圾回收算法:

  • 引用计数法:当一个对象被引用时,其引用计数加1,当引用计数为0时,该对象被标记为垃圾,等待被回收。引用计数法简单易实现,但是无法解决循环引用的问题。
  • 标记清除法:从(全局对象)出发定时扫描内存中的对象,凡是能从根部到达的对象,都是还要使用的,无法由根部出发到达的对象被标记为不再使用,会被回收。标记清除法可以解决循环引用的问题,但是会产生内存碎片。

JavaScript中的垃圾回收机制

JavaScript中的垃圾回收机制主要依赖于标记清除法,但是JavaScript引擎的实现可能会有所不同,比如V8引擎中使用了分代回收的策略,将内存分为新生代和老生代两部分,分别采用不同的垃圾回收算法进行回收。

  • 新生代:新生代中的对象存活时间较短,采用Scavenge算法进行回收,将内存分为两个空间,一个空间用于对象分配,另一个空间用于对象回收,当对象在两个空间中存活超过一定次数后,会被移动到老生代中。
  • 老生代:老生代中的对象存活时间较长,采用标记清除和标记整理算法进行回收,标记清除法用于标记不再使用的对象,标记整理法用于整理内存空间,减少内存碎片。

闭包

闭包是JavaScript中一个非常重要的概念,它是指函数可以访问其词法作用域中的变量,即使函数在其词法作用域之外执行。
闭包的原理是函数内部定义的变量在函数执行完毕后不会被立即释放,而是被保存在函数的执行上下文中,直到函数被销毁或者不再被引用。
闭包的应用场景包括但不限于:

  • 函数柯里化:将一个多参数的函数转换成多个单参数的函数,通过闭包保存中间结果,实现函数的复用。
  • 模块化:将代码封装在一个函数中,通过闭包暴露出需要暴露的接口,实现代码的模块化。
  • 回调函数:将函数作为参数传递给另一个函数,通过闭包保存函数的执行上下文,实现异步编程。
  • 私有变量:通过闭包实现私有变量的封装,防止外部代码直接访问和修改内部变量。
    这里以一个最简单的闭包形式作为例子展示闭包如何实现私有变量:
1
2
3
4
5
6
7
8
9
10
11
12
function outer(){
// 闭包
const a = 0;
function inner(){
console.log(a)
}
return inner
}
// 调用闭包
const fun = outer() // 全局作用域,从根开始可以达到局部作用域中的a,所以a不会被清除
// 外部函数使用outer内部的变量
fun()

在这个例子中,inner函数定义在outer函数内部,但是它仍然可以访问outer函数中的变量a,这是因为inner函数的执行上下文中保存了outer函数的执行上下文,从而实现了闭包。

总结

在本章中我们学习了JavaScript中的垃圾回收机制和闭包的概念,其中闭包是一个极其重要且应用范围极广的知识和技巧,在未来的学习和实际开发中我们将会经常遇到闭包这个概念,所以希望各位读者目前能够熟练掌握闭包的概念,在未来碰到闭包的时候能够看出来:“诶,这个形式好像是一个闭包!”通过不断在实战中遇上闭包,相信大家一定会对闭包有一个更深刻的理解。
那么本章节的内容到这里就结束了,下一章我们将初识构造函数,以及了解JavaScript中一些内置构造函数的常用方法,大家敬请期待!