(三)js闭包说明

66 阅读2分钟

内存管理->垃圾回收->内存泄漏->闭包


1.内存管理

内存管理流程如下:

  • 创建内存:审明变量、函数创建、对象创建会创建内存。
  • 使用内存:取值、赋值、使用函数会使用内存。
  • 释放内存:使用完毕,垃圾回收进行释放内存。

2.垃圾回收(Garbage Collection)

早期:引用计数法,核心(不在使用的对象)
如今:标记清除法,核心(无法达到的对象)

  • 引用计数法:有引用指向该对象,表示该对象在使用。当没有引用指向该对象,则不在使用的对象,进行回收。 存在缺点:当两个对象循环引用的时候,则一直不能进行回收,比如a.b=b; b.a=a

  • 标记清除法:从根部(也就是Global Object)出发,定时扫描内存对象。凡是能在根部能到达的对象,则为使用的对象。从根部将无法达到的对象,进行回收。可以解决循环引用的问题。

标记清除.png

3.内存泄漏

不在使用的内存得不到释放,导致内存浪费。(如闭包中函数的AO得不到释放,但不是所有闭包函数都会造成内存泄漏

4.闭包

一个函数该函数在创建时能访问的其他函数的变量 组合。

一、普通函数执行

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

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

执行bar和foo函数后其AO都被释放。 图片.png

二、闭包函数执行

function foo(){
    var name = 'foo'
    var age = 18
    function bar (){
        console.log(name);
    }
    return bar
}
const fn = foo()
fn()
  • 步骤

图片.png

  • 结果:根据标记清除法,从根出发扫描内存对象:

    GO.foo --> 0x001

    GO.fn --> 0x002

    0x002.parentScope --> 0x005 (也就是bar函数的AO)

    发现bar函数的AO永远不会被释放,这个闭包就会造成内存泄漏

图片.png

5.如何避免闭包导致的内存泄漏

  • 在不再需要闭包函数时,手动解除对闭包函数的引用,例如将变量赋值为 null
  • 尽量避免在 全局作用域 中创建闭包函数,而是将其限制在有限的作用域中,以便在不需要时能够更容易地释放相关资源。
  • 对于需要使用闭包函数的情况,尽量避免在闭包函数中持有对大量对象或数据的引用,以减少内存占用。