JS中的闭包是什么?

110 阅读2分钟

什么是闭包?

闭包是JS的一种语法特性。

闭包 = 函数 + 自由变量

对于一个函数来说,变量分为 全局变量、本地变量和自由变量。

let count = 0
function add(){
    count += 1
}

把上述代码放在一个 【非全局环境】 里面就是一个闭包。

闭包不是count,闭包也不是add,闭包是count + add组成的整体。
即 函数 和 函数内部能访问到的变量 的总和就是一个闭包。

那怎么制造一个非全局环境呢?答案是 立即执行函数:

const add2 = function() {
    let count = 0
    function add(){
        count += 1
    }
}()

但是这个代码什么用也没有,所以我们需要return add

const add2 = function() {
    let count = 0
    return function add(){
        count += 1
    }
}()

此时add2其实就是add,我们可以调用add2。

add2()
// 相当于
add()
// 相当于
count += 1

至此,我们就实现了一个完整的闭包的应用。

为什么需要函数套函数呢?

因为需要局部变量,所以才把count放在一个函数里,如果不把count放在一个函数里面,count就是一个全局变量,就达不到使用闭包的目的-隐藏变量 了。
即嵌套函数的目的是创造一个局部变量,和闭包无关。

为什么要return add呢?

因为如果不return,就无法使用这个闭包,把 return add 改成 window.add = add 也是一样的,只要让外面可以访问到这个 add 函数就行了。
所以 return add 只是为了add能被使用,也和闭包无关。

解决了什么问题

  1. 避免污染全局环境。
  2. 提供对局部变量的间接访问。
  3. 维持变量,使其不被垃圾回收。

优点

简单,好用

缺点

如果 使用不当 可能造成内存泄漏。
注意是使用不当, 不是闭包。 「闭包造成内存泄露」这句话以讹传讹很多年了,是曾经旧版本 IE 的 bug 导致的问题。 举例说明:

function test() {
  var x = {name: 'x'};
  var y = {name: 'y', content: "-----这里很长,有一万三千五百个字符那么长----" }
  return function fn() {
    return x;
  };
}

const myFn = test() // myFn 就是 fn 了
const myX = myFn() // myX 就是 x 了
// 请问,y 会消失吗?

对于一个正常的浏览器来说,y 会在一段时间后自动消失(被垃圾回收器给回收掉)。
但旧版本的 IE 并不是正常的浏览器,所以是 IE 的问题。