闭包原理以及使用场景

前端面试,必问闭包

闭包有多重要?如果你是初入前端的朋友,我没有办法直观的告诉你闭包在实际开发中的无处不在,但是我可以告诉你,前端面试,必问闭包。面试官们常常用对闭包的了解程度来判定面试者的基础水平,保守估计,10个前端面试者,至少5个都死在闭包上。

讲解闭包时,我们先来看个例子

在这里插入图片描述
上面代码中,函数f1可以读取全局变量n。但是下面例子,函数外部无法读取函数内部声明的变量。

在这里插入图片描述
上面代码中,函数f1内部声明的变量n,函数外是无法读取的.

如果有时需要得到函数内的局部变量。正常情况下,这是办不到的,只有通过变通方法才能实现。那就是在函数的内部,再定义一个函数。

在这里插入图片描述
上面代码中,函数f2就在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。既然f2可以读取f1的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!

闭包是什么

闭包是一种特殊的对象。
它由两部分组成。执行上下文(代号A),以及在该执行上下文中创建的函数(代号B)。
当B执行时,如果访问了A中变量对象中的值,那么闭包就会产生。
在大多数理解中,包括许多著名的书籍,文章里都以函数B的名字代指这里生成的闭包。而在chrome中,则以执行上下文A的函数名代指闭包。
我们可以对上面代码进行如下修改:

在这里插入图片描述
上面的例子,首先有执行上下文f1,在f1中定义了函数f2,而通过对外返回f2的方式让f2得以执行。当f2执行时,访问了f1内部的变量a。因此这个时候闭包产生

闭包就是函数f1,

上面的例子,首先有执行上下文f1,在f1中定义了函数f2,而通过对外返回f2的方式让f2得以执行。当f2执行时,访问了f1内部的变量a。因此这个时候闭包产生

闭包就是函数f1,

在这里插入图片描述
在上面的图中,红色箭头所指的正是闭包。其中Call Stack为当前的函数调用栈,Scope为当前正在被执行的函数的作用域链,Local为当前的局部变量。

JavaScript拥有自动的垃圾回收机制,关于垃圾回收机制,有一个重要的行为,那就是,当一个值,在内存中失去引用时,垃圾回收机制会根据特殊的算法找到它,并将其回收,释放内存。

而我们知道,函数的执行上下文,在执行完毕之后,生命周期结束,那么该函数的执行上下文就会失去引用。其占用的内存空间很快就会被垃圾回收器释放。可是闭包的存在,会阻止这一过程。

我们再来看个例子:

在这里插入图片描述
在上面的例子中,foo()执行完毕之后,按照常理,其执行环境生命周期会结束,所占内存被垃圾收集器释放。但是通过fn = innerFoo,函数innerFoo的引用被保留了下来,复制给了全局变量fn。这个行为,导致了foo的变量对象,也被保留了下来。于是,函数fn在函数bar内部执行时,依然可以访问这个被保留下来的变量对象。所以此刻仍然能够访问到变量a的值。

这样,我们就可以称foo为闭包。

所以,**通过闭包,我们可以在其他的执行上下文中,访问到函数的内部变量。**比如在上面的例子中,我们在函数bar的执行环境中访问到了函数foo的a变量。个人认为,从应用层面,这是闭包最重要的特性。利用这个特性,我们可以实现很多有意思的东西。

不过读者朋友们需要注意的是,虽然例子中的闭包被保存在了全局变量中,但是闭包的作用域链并不会发生任何改变。在闭包中,能访问到的变量,仍然是作用域链上能够查询到的变量。

对上面的例子稍作修改,如果我们在函数bar中声明一个变量c,并在闭包fn中试图访问该变量,运行结果会抛出错误。

在这里插入图片描述
闭包形成的条件

  • 函数嵌套
  • 内部函数引用外部函数的局部变量

闭包的应用场景

初级前端了解以上闭包面试即可,以下内容属于中高级前端理解范围。大家可以暂时跳过,等学有一定基础积累,再回头看看。

除了面试,在实践中,闭包有两个非常重要的应用场景。分别是模块化与柯里化。

柯里化
模块化

在我看来,模块是闭包最强大的一个应用场景。如果你是初学者,对于模块的了解可以暂时不用放在心上,因为理解模块需要更多的基础知识。但是如果你已经有了很多JavaScript的使用经验,在彻底了解了闭包之后,不妨借助本文介绍的作用域链与闭包的思路,重新理一理关于模块的知识。这对于我们理解各种各样的设计模式具有莫大的帮助。

在这里插入图片描述
在上面的例子中,我使用函数自执行的方式,创建了一个模块。add是模块对外暴露的一个公共方法。而变量a,b被作为私有变量。

在这里插入图片描述

为了验证自己有没有搞懂作用域链与闭包,这里留下一个经典的思考题,常常也会在面试中被问到。

利用闭包,修改下面的代码,让循环输出的结果依次为1, 2, 3, 4, 5

在这里插入图片描述

  • 14
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值