JavaScript的闭包是什么

117 阅读3分钟

闭包的定义:

在计算机科学中

  • 闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures);
  • 是在支持 头等函数 的编程语言中,实现词法绑定的一种技术;
  • 闭包在实现上是一个结构体,它存储了一个函数和一个关联的环境(相当于一个符号查找表);
  • 闭包跟函数最大的区别在于,当捕捉闭包的时候,它的自由变量 会在捕捉时被确定,这样即使脱离了捕捉时的上下文,它也能照常运行;
  • 闭包的概念出现于60年代,最早实现闭包的程序是 Scheme,那么我们就可以理解为什么JavaScript中有闭包:
    • 因为JavaScript中有大量的设计是来源于Scheme的;

在JavaScript中

MDN对JavaScript闭包的解释:

  • 一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure);
  • 也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域;
  • 在 JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来;

总结

  • 一个普通的函数function,如果它可以访问外层作用域的自由变量,那么这个函数和周围环境就是一个闭包;
  • 从广义的角度来说:JavaScript中的函数都是闭包;
  • 从狭义的角度来说:JavaScript中一个函数,如果访问了外层作用域的变量,那么它是一个闭包;

关于面试:

是什么:

闭包是JS的一种语法特性

闭包=函数+自由变量闭包=函数+自由变量

对于一个函数来说,变量分为:全局变量,局部变量,自由变量

怎么做:

let count
function add(){ //访问了外部变量的函数
    count+=1
}

把上面代码放到[非全局环境]里,就是闭包 count不是add的局部变量,也不是全局变量,那对于add来说,它就是自由变量

注意,闭包不是count,也不是add,闭包是count+add组成的整体。

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

const x = function(){
    var count
    function add(){ //访问了外部变量的函数
        count +=1
    }
}

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

const add2 = function(){
    var count
    return function add(){ //访问了外部变量的函数
        count+=1
    }
}()

add2()

所以闭包是把一个自由变量和一个函数,放到一个非全局环境中,这就是闭包! 至此,我们就实现了一个完整的闭包的应用。

注意:闭包≠闭包的应用,但面试官问闭包的时候,要答闭包的应用。

解决了什么问题:

  1. 避免污染全局环境。(因为用的是局部变量)
  2. 提供对局部变量的间接访问。(因为只能count+=1,不能count-=1)
  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的问题。 当然你可以说:

君子不立于危墙之下,我们应该尽量少用闭包,因为有些浏览器对闭包的支持不够好

但是不可以说闭包造成内存泄漏。

怎么解决缺点:

建议慎用,少用,不用。

参考:zhuanlan.zhihu.com/p/22486908