Skip to content

闭包

闭包是什么?如何产生的?

红宝石原话:能够访问其他函数内部的变量的函数,就是闭包。

一个函数,它里面用到了外部数据,于是这个函数本身就跟外部数据产生了关联,这就产生了“闭包”。

闭包的特性:函数不销毁,关联的词法环境(即函数的外部数据)就不会销毁。

闭包代码题

什么是 “标记清除”?

从根对象遍历标记所有可达对象,未被标记的对象则被回收。

js
function foo() {
  const value = new Array(1000000);
  function bar() {
    value
  }
}

foo();

// 1. foo 函数运行结束后,大数组是否是垃圾?—— 是垃圾。
// 2. 如果这个大数组是垃圾的话,是否被回收?—— 会被回收。(通过“标记清除”的回收机制进行回收)
// 3. 整个代码中是否存在闭包?—— 存在闭包。
js
function foo() {
  const value = new Array(1000000);
  function bar() {
    value
  }
  return bar;
}

foo();

// 1. foo 函数运行结束后,大数组是否是垃圾?—— 是垃圾。(foo 函数运行之后,value 都找不到了,所以还是垃圾)
// 2. 如果这个大数组是垃圾的话,是否被回收?—— 会被回收。(还是通过“标记清除”的机制,foo 函数运行过后,bar 函数都是垃圾,更何况内部的数据呢,所以会被回收)
// 3. 整个代码中是否存在闭包?—— 存在闭包。
js
function foo() {
  const value = new Array(1000000);
  function bar() {
    value
  }
  return bar;
}

const b = foo();
// 这种情况下,由于为 bar 建立了一个引用,bar 函数和 value 就不是垃圾了(因为如果回收的话,外部就用不了了)

闭包是否会造成内存泄漏?

先说什么是内存泄漏:有垃圾,但是没有被回收。

再来说说闭包的特性:如果函数没有销毁,那么这个函数的“词法环境”也不会销毁。但是这个特性,严格意义上应该算不上是内存泄漏。

所以核心点就是,“这个变量”到底是不是垃圾?以后不用的话,那是垃圾,就属于内存泄漏。如果以后可能用,那么就不是垃圾,不属于内存泄漏。例如:

js
let nums = [1, 2, 3]
const sum = nums.reduce((a, b) => a + b, 0)
console.log(sum)

// nums 是不是垃圾?
// 以后到底用不用 nums?用 —— 不是垃圾;不用 —— 那就是垃圾。

基于 MIT 许可发布