跳到主要内容

闭包的标准答案

作为常考的八股文,在网上有两种关于闭包的标准答案

答案1:闭包,能够读取其他函数内部变量的函数

答案2:闭包的本质就是在一个函数内部创建另一个函数

那么哪种答案是对的呢,其实两种答案都是对的,可以说是一种现象的不同解释。但是作为面试常用考点,其实回答其中之一的答案并不是最优解,因为面试官背的标准答案可能和你背的不是同一个。

因此,在面试之余可以深入挖掘一下闭包的关联概念,了解闭包的起源和真实的“标准答案”。

为什么会出现闭包

明明是一个函数,为什么要用用闭包这个名词来说明呢?

可以从一个最简单的表达式开始说起,表达式 1 + 1 ,计算机能直接识别。

那么一个新的表达式 1 + X 如何执行呢?其中X就是未决变量,执行就需要告诉计算机X是什么。这样可以说就是一个函数了。

如果是一个参数,那么在js中就可以用箭头函数表示为(X) => { 1+ X}。那么在数学上就可以用λX.1 + X 来表示X为参数。同样用数学的lamda公式也可以表示出函数。

那么如果有新的未决变量Y,那么在数学上就可以表示为λX.Y + X,那么这条语句因为计算机不能识别出来Y的定义,因此是不能执行的。这就需要用到环境中的变量来定义这个Y,让这个函数可以执行。那么闭包的概念就可以很明显的出来了:

闭包 = 环境(包含Y的环境) + 控制(λX.Y + X)

因此Javascript为了实现闭包,把函数定义成了定义时候的环境。这当然不是闭包唯一的实现策略。

闭包的标准答案

闭包closure是1964年提出的一个计算机编程的概念,按照当时论文《表达式的机器执行》的定义它包含控制和环境两个部分,在Javascript中,以函数能够访问定义时的环境中变量的方式得以实现。

常用的闭包有哪些

除了上述闭包的概念外,还可以了解以下我们开发中用到了哪些闭包?

防抖

应用场景:一个搜索输入框,用户不停的进行输入(这个时候就是抖动的过程),等用户输入停止之后,再触发搜索

function debounce(fn, delay = 200) {
let timer = 0; // timer在返回的函数中被使用
return function () {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = 0
}, delay)
}
}

模拟模块(私有方法)

var Counter = (function() {
var privateCounter = 0 // 私有变量
function changBy(val) {
privateCounter += val
}
return {
intcrement: function() { // 三个闭包共用一个词法语境
changBy(1)
},
delcrement: function() {
changBy(-1)
},
value: function() {
return privateCounter
}
}
})()

console.log(Counter.value()) // 0