第二次简单了解闭包

闭包

1. 函数的词法作用域规则

基本规则:函数在执行过程中所用到的作用域是在函数定义时的作用域,而不是函数调用时的作用域。

如何理解这个规则呢?来看两个例子。

例子一:

在这里插入图片描述

这个例子的执行结果是 小龙。由于函数 fun() 不管是定义还是调用都是在同一个作用域中(如下图)。所以这无法知道函数执行过程中所依赖的作用域是哪一个作用域。

在这里插入图片描述

例子二:

在这里插入图片描述

在这个例子中,函数 fun() 定义时的作用域和调用时的作用域并不在同一个作用域中(如下图)。那么执行结果会是什么?答案是 小龙,而不是 小鱼

我们知道 小龙 是在函数 fun() 定义时的作用域下,而小鱼是在函数fun() 调用时的作用域下,这说明函数在执行过程中所依赖的作用域是定义时的作用域。

在这里插入图片描述

2. 作用域链

如果在当前作用域中没有查找到所需的值,就会向上层作用域查找,直到全局作用域,这么一个查找过程形成的链条就叫做作用域链。

在这里插入图片描述

函数 getter() 执行时会先在当前作用域中查找所需的变量,如果当前作用域没有,就会往上一层作用域查找,以此类推,直到全局作用域。如果连全局作用域都没有该变量,则会报错:xxx is not defined

上面例子中查找变量过程中形成的链条( 3 --> 2 --> 1)就是作用域链。

在这里插入图片描述

3. 解释闭包

  • 《JavaScript高级程序设计》
    • 闭包是指有权访问另一个函数作用域中的变量的函数。
  • 《JavaScript权威指南》
    • 从技术的角度讲,所有的函数都是闭包:它们都是对象,它们都关联到作用域链。
  • 《你不知道的JavaScript》
    • 当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。

个人理解闭包应该是基于词法作用域书写代码时产生的自然结果,是一种现象。

例子一:

在这里插入图片描述

这个例子中,函数 getter() 能够获取到变量 userName 有两种解释:1. 作用域链 2. 闭包,所以这里不太好观察闭包这个现象。

例子二:

在这里插入图片描述

在这个例子中,函数 getter 是在函数 userInfo 的词法作用域外面执行,但依然能拿到变量 userName,这不就是上面所说的函数的词法作用域规则,所以闭包就是基于函数词法作用域规则下产生的一种现象。

简单理解就是一个函数中嵌套另一个函数,这两个函数之间就产生了闭包。

4. 闭包作用

让外部可以获取到函数内部的局部变量

让函数内部的变量可以一直保存在内存中

在这里插入图片描述

这个例子就是利用了闭包实现了全局变量 getUserName 对函数 getter 的引用,从而达到让外部获取到函数内部的变量。

疑问一:当一个函数调用结束之后,函数的本身以及内部的局部变量都会被垃圾回收机制回收。那为什么函数 userInfo 调用结束之后还可以获取到其局部变量 userName


解答:原因在于 userInfogetter 的父函数,而 getter 被赋给了一个全局变量,这导致 getter 始终在内存中,而 getter 的存在依赖于 userInfo,因此 userInfo 也始终存在内存中,不会在调用结束之后被垃圾回收机制回收。

5. 使用的注意点

  • 由于闭包会使得函数中的变量一直保存中内存中,内存消耗很大,所以不能滥用闭包
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值