持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情
前言
说到闭包,好像这又是一个面试必考的题目,印象中好像每次面试都被问到,然后每次面试官都都让讲讲,每次都说了一些,最后面试官也没有说到底说的对不对,所以之前说的到底是给面试加分还是减分都不清楚。
闭包
红宝书第4版第309页的最后一行的解释是闭包指的的是那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的。
由此我们可以知道这句话有两个重点:
// 1.首先闭包得是一个函数
// 2.其次这个函数引用了另一个函数作用域中得的变量
function getName() {
let name = 'lili'
return function(){
let str = `我的名字是${name}`
return str
}
}
let str = getName()
console.log(str()) // 我的名字时lili
在这个函数中,内部的匿名函数引用了外部函数的变量name
,在我们调用外部函数getName
后,这个匿名函数仍然引用着name
这个变量,这样就形成了一个闭包。要真正理解闭包,我们又必须得先理解Javascript作用域
。
作用域
关于作用域的定义,红宝书第4版第87页的解释是变量或函数的上下文决定了他们可以访问哪些属性,以及它们的行为。每一个上下文都有一个关联的变量对象,而这个上下文中定义的所有变量和函数都存在于这个对象上。
我觉得每一个上下文都可以理解为一个作用域。上下文在所有代码都执行完毕之后会被销毁,包括定义在它上面的所有变量和函数。而每一个函数都有自己的上下文,当我们访问函数中的某一个变量时,解释器首先会从当前作用域中查找,如果没找到,就再父级作用域查找,直到找到为止或者找不到返回undefined
,这就形成了作用域链。
总结
我们用作用域链来解释闭包就比较好理解了,我们把getName
函数执行结果返回给str
变量,当函数执行完后,getName
函数的执行上下随之被销毁,内部匿名函数也被销毁,但是这个匿名函数函数定义并没有被销毁,而是被赋值给了str
变量(这里就是闭包的形成)。