闭包是怎么回事

426 阅读2分钟

这是我参与更文挑战的第4天,活动详情查看: 更文挑战

闭包是什么?这是一个在javaScript中一个很难搞懂的问题。

ECMAScript 中给闭包的定义是:闭包,指的是词法表示包括不被计算的变量的函数,也就是说,函数可以使用函数之外定义的变量。是不是看了这个定义更加的难以理解了。下面我们分析一下。

  1. 闭包是一个函数
  2. 闭包可以调用自身函数之外的定义变量
  3. 闭包存在定义该变量的作用域中

那么什么叫函数定义之外的变量呢?下面我们先来看看函数变量的作用域是怎么回事。

变量作用域

变量可分为全局变量和局部变量。全局变量的作用域就是全局性的,在 js 的任何地方都可以使用全局变量。在函数中使用 var 关键字声明变量,这时的变量即是局部变量,它的作用域只在声明该变量的函数内,在函数外面是访问不到该变量的。

var func = function(){
    var a = 'dddd';
    console.log(a);         // dddd
}
func();
console.log(a);             // Uncaught ReferenceError: a is not defined

来看看跟闭包关系比较大的变量生存周期。

变量生存周期

全局变量,生命周期是永久的。局部变量,当定义该变量的函数调用结束时,该变量就会被垃圾回收机制回收而销毁。再次调用该函数时又会重新定义了一个新变量。

var func = function(){
    var a = 'ddd';
    console.log(a);
}
func();

a就是局部变量,当函数func调用完之后a就会被销毁。

var func = function(){
    var a = 'ddd';
    var func1 = function(){
        a += ' a';
        console.log(a);
    }
    return func1;
}
var func2 = func();
func2();                    // ddd a
func2();                    // ddd a a
func2();                    // ddd a a a

可以看出,在第一次调用完 func2 之后,func 中的变量 a 变成 'ddd a',而没有被销毁。因为此时 func1 形成了一个闭包,导致了 a 的生命周期延续了。

这下子闭包就比较明朗了。

  • 闭包是一个函数,比如上面的 func1 函数
  • 闭包使用其他函数定义的变量,使其不被销毁。比如上面 func1 调用了变量 a
  • 闭包存在定义该变量的作用域中,变量 a 存在 func 的作用域中,那么 func1 也必然存在这个作用域中。 现在可以说,满足这三个条件的就是闭包了。