JS闭包

本文最后更新于:2022年3月26日 下午

JS 闭包详解

简单来说,在一个函数中定义的函数被return保存到了外部,就会产生闭包

更为准确的一种说法是:在函数返回值值中包含另一个函数的声明(比如返回了一个对象)就可以形成闭包

function test() {
  let arr = []
  for (let i = 0; i < 10; i++) {
    arr[i] = function () {
      console.log(i)
    }
  }
  return arr
}

let myArr = test()
for (let j = 0; j < 10; j++) {
  myArr[j]();
}
// 结果是10个10

闭包的好处就是我们可以在全局访问一个内部的变量,但是坏处是会造成内存泄漏

底层原理

说到底,就是js的上下文作用域链

在一个函数被声明时,它会记住当前的环境并将其保存,然后调用的时候又回产生一个作用域,之前声明时的作用域环境被下移。

由于在函数内部的函数被声明时的环境为外层函数的作用域,所以会直接继承所有外层函数的作用域,于是包含了外层函数的变量,外层函数的变量变得可访问

立即执行函数

(function (){
  ...
}())

只有表达式才能被执行符号()执行

被立即执行之后会立即销毁这个函数

所以,只要是表达式,就能被执行符号立即执行

!function (){

}()
// 这种形式也是立即执行函数,因为!variable就是一种表达式

我们通常用立即执行函数来避免闭包的产生(如果我们不希望闭包的内存泄漏效应)

让我们再次看看上面闭包的例子

function test() {
  let arr = []
  for (let i = 0; i < 10; i++) {
    (function (j){
      arr[j] = function () {
        console.log(j)
      }
    }(i))
  }
  return arr
}

let myArr = test()
for (let j = 0; j < 10; j++) {
  myArr[j]();
}
// 这下就变成了正常的0~9

简单来说,想避免闭包效应,我们可以构造一个形参为可泄漏变量的立即执行函数,然后应用形参就可以将可泄漏变量销毁


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!