面试官问,什么是闭包,我该怎么答?

面试官问,什么是闭包,我该怎么答?
我想答出一段话,或者定义,而不是一个函数实例

阅读 7.4k
13 个回答

推荐高程,网上的理解都是个人的,可以参考,但有自己的理解才是最好的。

我认为比较好的回答是:

1、闭包条件:a、外层函数嵌套内层函数;b、内层函数引用外层函数中的变量;c、外层函数返回内层函数;
2、js垃圾回收机制:当一个变量不被引用的时候会被回收
3、每个函数声明的时候,会生成一个包含该函数作用域内部变量的活动对象

举一个简单例子分析:

function a() {
    var x = 1
    var y = 100
    console.log(y)
    y++
    return function b() {
        console.log(x++)
    }
}
var result= a() // 100
var result1 = a() // 100
-----------------------------
result() // 1
result() // 2

上述例子在不存在闭包的情况应该是,我执行完a以后,销毁了函数作用域,那么x也被销毁了,那么两次执行的结果应该是两次1。但第二次是2,说明内部的x并没有被销毁,也就是a函数作用域被中的x被保存下来了。

结合上述3点开始分析:
a函数声明时,创建了一个包含a函数作用域内部变量的活动对象,可以叫他aa,aa内部有局部参数x;
b函数声明时,引用了aa中的x;
a函数执行后,全局变量result引用了b函数;
那结合JS的垃圾回收机制,x被引用不会被销毁,b被引用不会被销毁,result是全局变量也不会被销毁,x得以保留,这样就形成了闭包.而由于aa中的y没有被引用,所以被销毁了。

上面是我的理解,最后可以回答一下闭包的应用,这里就不做回答了,网上很多

综上所述,建议的回答就是上述3点加上应用

闭包是指有权访问另一个函数作用域内变量的函数。 -- 《JavaScript高级程序设计》

闭包就是函数嵌套函数,函数内部可以使用函数外部的变量。

能访问外部函数的变量的函数,举个例子:

function a(x){
      var z=3;
      function b(y){  // 这个就是闭包,它能访问外部函数a的x和z变量
          console.log(x+y+(++z));
     }
    return b;
}

一级函数调用二级函数,二级函数访问一级函数词法作用域变量的过程叫做闭包, 再简单点就是函数套函数

记得在哪本书上看到的, 理解 闭包 最好的办法是和 的概念进行对比:

  • 就是带有方法的数据.
  • 闭包 就是带有数据的方法.

解释:当前函数内部能够访问其他作用域内的变量就形成闭包。
作用:
1.扩大变量作用域
2.防止变量变量被销毁(垃圾回收机制)

定义 函数a函数b
满足:

  • 函数a 作用域内引用了 函数b 作用域内的变量。(a捕获b的自由变量)
  • 函数a 可在 函数b 作用域之外执行。(b的变量对象无法正常销毁)

就形成闭包了。
怎么答看各人表达,意思到就行了。。。

// 例子自行体会
function b(){
    var z = 3;
    function a(y){
        console.log(z + y);  // a 引用了 b作用域内的 变量z
    }
    return a;
}
var c = b();
c(1);  // a 可以在 函数b 外执行

通俗的讲: 函数里面有一个函数; 进一步的理解:被包住的函数可以访问包住的函数的变量;

看了所有的答案,大家的理解都差不多,只在一点上有分歧: 闭包是否必须被外界访问到?
答案是: 否!

function a(x){
      var z=3;
      function b(y){  // 这个就是闭包,它能访问外部函数a的x和z变量
          console.log(x+y+(++z));
     }
    return b;
}

去掉return 是否还是闭包?
答案是: 是!!!!!!!!!!
它既是内部函数,也是闭包,这两者并不冲突。

mdn上闭包的定义:

闭包是函数和声明该函数的词法环境的组合。

只要满足,这是一个函数,这个函数内部使用了外部变量,它就是一个闭包。
mdn上的第一个例子:

function init() {
    var name = "Mozilla"; // name 是一个被 init 创建的局部变量
    function displayName() { // displayName() 是内部函数,一个闭包
        alert(name); // 使用了父函数中声明的变量
    }
    displayName();
}
init();

因为diaplayName无法再次访问到,因此闭包中的name也会被回收掉。
从定义上讲,displayName是个闭包,虽然没有啥卵用。

---------------分割线--------------------------

另外,根据定义,任何函数都可以是广义上的闭包,因为词法环境中的外部引用有可能是空。
所以如果面试官问你闭包,那我建议你应该先问他,是回答闭包的定义还是多数实践,是回答狭义还是回答广义。

新手上路,请多包涵

个人见解

  • 闭包从最开始有到后来用的人多,到现在不推荐使用,会造成逻辑混乱
新手上路,请多包涵

函数嵌套函数

推荐问题
宣传栏