面试题:为什么要用闭包?

看了这个回答似乎也不是了解的很透彻啊

我是学Java的。今天在面试的时候面试官提及匿名类,我说Java8里面提供了Lamada式,在JS里也有闭包这个概念。面试官问什么是闭包?为什么要用闭包?

  • 我说:用来控制访问啊。内部可以访问外部,但是外部不能访问内部。

面试官似乎不是很满意这样的回答。不知各位大神对这个问题有什么看法?

闭包,顾名思义,就是把馒头变成包子~

馒头全是面粉,包上馅就成了包子

包子是带馅的馒头

闭包是自带运行环境的函数

发哥是自带背景音乐的男人~


有童鞋不理解“自带运行环境”的含义~

再举例说一次吧~

码农们都吃过方便面吧~
它和普通面条有什么区别呢?
就是 自带调味包 。
调味包就是方便面的烹饪环境。
它简化了煮面条的流程。让用户不必练就厨艺也能吃上美味的内牛满面。

函数式编程的闭包,就是函数的调味包。
方便用户调用函数。不必为了维护繁杂的外部状态而烦恼。
例如python,就把闭包玩出了很多花样:
静态私有变量啦~
偏函数啦~
单参化~
装饰器~
……

当你在用这些功能的时候,其实就是在吃别人设定好调味包的“方便面”。

其实我的理解:闭包的目的是用来扩大变量的作用域的。

立即执行函数和闭包有什么关系

重点看下@边城的理解,我的答案比较单薄,要是还感兴趣,可以看下高程三对作用域链、闭包这段的阐述~

刚看的一篇文章 史上被骂最多的编程语言——JavaScript

楼主的回答并不准确,如果我是面试官我也不满意。
简单来说,闭包是指当函数被当成对象返回时,如果夹带了外部变量就形成了闭包。我非常赞同那位比喻把馒头加上馅变成包子的同学的回答,他虽是调侃成分居多,但理解的程度非常之深刻。

如果一个函数打包了外部变量,就可以给程序非常大的灵活性,你可以把闭包理解成轻量级的接口封装,虽然对外都是这个函数(调用方式不变),但是因为之中的变量不一样,就可以完成很多功能。这也就是那位同学说的自带运行环境的函数,自带背景音乐的男人,想想都可怕。

如果你想还深入了解一点,可以参考我总结的一篇文章,详解Python中的闭包,虽然编程语言不一样,但是道理是一样的。

你的回答是关于作用域的回答,不是关于闭包的。而且这个回答也是属于不严谨的回答。你根本解释不清什么是内部,什么是外部。

我认为闭包是这样的。当一个函数在定义它的作用域以外的地方被调用时,它访问的依然是定义它时的作用域。这种现象称之为闭包。

具体用途有好多,常见的有创建私有属性,函数柯里化等等。

————分割线————

我再补充一下,其实闭包的本质是静态作用域。因为 JavaScript 没有动态作用域,所以函数访问的都是定义时的作用域,所以闭包才得以实现。

其他答案里说闭包是自带运行环境的函数。但是实际上,JavaScript 里任何函数不都是自带运行环境的函数吗?有的人也因此认为所有的函数都是闭包。这当然也不算错,但对理解闭包其实意义不大。因为你平时都是这么使用函数的,即使你不知道什么是闭包,也不会出什么问题。只不过平时你可能没有意识到全局作用域就是一个大闭包。

我们常见的闭包形式就是a 函数套 b 函数,然后 a 函数返回 b 函数,这样 b 函数在 a 函数以外的地方执行时,依然能访问 a 函数的作用域。其中“b 函数在 a 函数以外的地方执行时”这一点,才体现了闭包的真正的强大之处。

总之,闭包只是基于静态作用域的一个编程技巧。从面试的角度来说,你要回答什么是闭包,你首先得解释什么静态作用域的特点,然后还必须要强调“b 函数在 a 函数以外的地方执行时”这一点,才算是对闭包的完整回答。

lambda演算式只允许单输入单输出,所以lambda a, b: a + b就等于lambda a: lambda b: a + b也就是currying。

简单来说,闭包的定义是:函数能访问它被定义时的作用域。

所以,你说的访问控制之类的,只是闭包的一个应用场景而已,当然没有回答什么是闭包的问题,面试官自然就不满意。

另外,Java里面其实是不支持闭包的,匿名内部类看起来跟闭包差不多,但实际上不管是功能性还是实现层面都不能算是闭包。因为:

  1. 从功能上,匿名内部类里面访问的变量必须是final(Java8隐含声明final)

  2. 实现上,匿名内部类里访问的final变量值其实是从外面被拷贝进去了,所以其并不能真正访问到之前的作用域,这也是为什么必须是final的原因。

所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
在Javascript中创建一个闭包来解释闭包最好不过:

function a{
var i=0;
function b{
alert++i;
}
return b;
}
var c=a;
c;

函数b嵌套在函数a内部;函数a返回函数b。
这样在执行完var c=a 后,变量c实际上是指向了函数b,再执行c 后就会弹出一个窗口显示i的值(第一次为1)。这段代码其实就创建了一个闭包,因为函数a外的变量c引用了函数a内的函数b,也就是说:当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。

其实按照闭包的一般写法形式,简单的来说就是 函数里面又嵌套了函数。在团队开发中,为了防止命名冲突,我们一般会把相应的代码用闭包的形式包裹起来,以避免暴露在全局作用域下面。但是有个不好的地方是其内部变量不会被立马回收,有内存溢出的风险。

发表评论

电子邮件地址不会被公开。 必填项已用*标注