JavaScript中的闭包是什么?JavaScript中闭包造成的内存泄漏又怎么解决?

简介: JavaScript中的闭包是什么?JavaScript中闭包造成的内存泄漏又怎么解决?

本文围绕三个二级目录展开描述闭包与内存泄漏,请看下文:


闭包是什么?

一.维基百科对闭包的定义:

闭包又称此法闭包或函数闭包;

是在支持头等函数的编程语言中,实现词法绑定的一种技术;

闭包在是实现上是一个结构体,它存储了一个函数和一个关联的环境;

闭包跟函数的最大区别在于,当捕捉闭包的时候,它的自由变量会在捕捉时被确定,这样及时脱离了捕捉时的上下文,它也能照常运行;

二.MDN对JavaScript闭包的解释:

一个函数和对其周围状态的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包。

也就是说,闭包让你可以在一个内层函数中访问到期外层函数的作用域。

在JavaScript中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。

相信大家看了上面的官方解释并不怎么理解闭包是什么?自由变量又是什么?接下来使用一个小demo进行解释:

function foo () {
    var name = 'foo'
    function bar () {
        console.log('bar', name)
    }
    return bar
}
var fn = foo()
fn() // bar foo

上述示例代码中, bar 函数本身与自由变量name组成了严格意义上的闭包。

一个函数和对其周围状态的引用捆绑在一起(或者说函数被引用包围)对于这句话的理解,此时的一个函数指的就是bar函数,自由变量name就是捆绑在一起的。二者组合就是闭包。


闭包一定会在函数创建的同时被创建出来吗?

在JavaScript中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。

这句话我们是怎么理解的呢?如果不访问自由变量也是闭包吗?

接下来继续展示一个小demo进行分析,示例代码如下:

// can函数
var can = 'can'
function can () {
    console.log(can)
}
// not函数
function not () {
}
/* 
  两个不同的函数一个访问了自由变量,一个没有访问自由变量,两个谁是闭包谁又不是闭包呢?
  首先,can函数访问了自由变量can,所以他们两个组合称为闭包;
  其次,not函数有两种不同的理解:
    1. 可以访问自由变量(但这里没有访问)也可称为闭包
    2. 没有访问自由变量,称不上闭包      
*/

个人小结:

一个普通的函数function,如果它可以访问外层作用域的自由变量,那么这个函数就是一个闭包;

从广义上的角度来说,JavaScript中的函数都是闭包;

从狭义的角度来说,JavaScript中一个函数,如果访问了外层作用域的变量,那么它是一个闭包。


闭包造成的内存泄漏怎么解决呢?

内存泄露是指:用动态存储分配函数内存空间,在使用完毕后未释放,导致一直占据该内存单元。直到程序结束。指任何对象在你不再拥有或需要它之后仍然存在。

还是写一个小demo来进行分析,示例代码如下:

function foo () {
    var name = 'foo'
    var age = 20
    function bar () {
        console.log(name)
        console.log(age)
    }
    return bar
} // 第二行至第八行为闭包函数 name 和 age 上升为自有变量
var fn = foo()
fn()

fn函数调用完毕之后,foo函数会自动销毁,但foo函数中的变量name和age不会被销毁,因为在bar函数内部进行了访问,并且根据垃圾回收机制,被另一个作用域引用的变量不会被回收。除非bar函数解除调用才能销毁。

如果该函数使用的次数很少,不进行销毁的话就会变为闭包产生的内存泄漏。

说了这么多解决办法是什么呢?只需将该函数赋值为null即可。

示例代码如下(承接上一个代码片段):

fn = null  // 阻止内存泄漏

闭包可能会造成内存泄漏,但不是一定会造成。


目录
相关文章
|
21天前
|
自然语言处理 JavaScript 前端开发
JavaScript中闭包:概念、用途与潜在问题
【4月更文挑战第22天】JavaScript中的闭包是函数及其相关词法环境的组合,允许访问外部作用域,常用于数据封装、回调函数和装饰器。然而,不恰当使用可能导致内存泄漏和性能下降。为避免问题,需及时解除引用,减少不必要的闭包,以及优化闭包使用。理解并慎用闭包是关键。
|
1月前
|
JavaScript
闭包(js的问题)
闭包(js的问题)
13 0
|
2月前
|
JavaScript 前端开发 Java
内存管理和内存泄露(闭包、作用域链)(三)
内存管理和内存泄露(闭包、作用域链)
24 0
|
2月前
|
自然语言处理 JavaScript 前端开发
内存管理和内存泄露(闭包、作用域链)(二)
内存管理和内存泄露(闭包、作用域链)
30 0
|
2月前
|
存储 缓存 JavaScript
请描述一种JavaScript内存泄漏的情况,并说明如何避免这种情况的发生。
JavaScript内存泄漏常由闭包引起,导致无用对象滞留内存,影响性能。例如,当一个函数返回访问大型对象的闭包,即使函数执行完,对象仍被闭包引用,无法被垃圾回收。防止泄漏需及时解除引用,注意事件监听器清理,使用WeakMap或WeakSet,定期清理缓存,以及利用性能分析工具检测。
13 2
|
2天前
|
JavaScript 前端开发 算法
JavaScript的垃圾回收机制通过标记-清除算法自动管理内存
JavaScript的垃圾回收机制通过标记-清除算法自动管理内存,免除开发者处理内存泄漏问题。它从根对象开始遍历,标记活动对象,未标记的对象被视为垃圾并释放内存。优化技术包括分代收集和增量收集,以提升性能。然而,开发者仍需谨慎处理全局变量、闭包、定时器和DOM引用,防止内存泄漏,保证程序稳定性和性能。
7 0
|
6天前
|
前端开发 JavaScript
闭包在JavaScript中有许多应用场景
闭包在JavaScript中发挥关键作用,如封装私有变量和函数提升安全性,维护变量生命周期,实现高阶函数,模拟块级作用域,支持回调函数以处理异步操作,以及促进模块化编程,增强代码组织和管理。闭包是理解和掌握JavaScript高级特性的重要一环。
21 7
|
13天前
|
自然语言处理 JavaScript 前端开发
【JavaScript技术专栏】深入理解JavaScript作用域与闭包
【4月更文挑战第30天】了解JavaScript的关键在于掌握作用域和闭包。作用域决定变量和函数的可访问范围,分为全局(在`window`或`global`对象中)和局部(函数内部)。闭包则允许函数访问其创建时的作用域,即使在其他地方调用。它通过作用域链保存对外部变量的引用,常用于实现私有变量、模块化和柯里化。然而,不当使用闭包可能导致内存泄漏和性能下降。理解这些概念能提升代码质量,但也需谨慎处理潜在问题。
|
14天前
|
自然语言处理 前端开发 JavaScript
【Web 前端】什么是JS闭包?
【4月更文挑战第22天】【Web 前端】什么是JS闭包?
|
14天前
|
存储 缓存 JavaScript
【Web 前端】JS哪些操作会造成内存泄露?
【4月更文挑战第22天】【Web 前端】JS哪些操作会造成内存泄露?