关于javascript闭包


理解闭包之前需要先知道以下两个知识点:
1.JavaScript中的作用域和作用域链

  • 作用域就是一个独立的‘地盘’,让变量不会外泄、暴露出去,不同作用域下同名变量不会有冲突。
  • 作用于在定义时就确定,并且不会改变
  • 如果在当前作用域中没有查到值,就会向上级作用域去查,知道查到全局作用域,这个查询过程形成的链条就叫做作用域链

2.Javascript中的垃圾回收

  • Javascript 执行环境会负责管理代码执行过程中使用的内存,其中就涉及到一个垃圾回收机制。
  • 垃圾收集器会定期(周期性)找出那些不再继续使用的变量,只要该变量不再使用了,就会被垃圾收集器回收,然后释放其内存。如果该变量还在使用,那么就不会被回收。

什么是闭包

闭包是一种现象,是在定义函数时,周围环境中的信息可以在函数中使用。换句话说,执行函数时,只要在函数中使用了外部的数据,就创建了闭包。
而作用域,正是实现闭包的手段。

第一种情况
image-20211227145521272 执行到断点时,会顺着作用域链一层一层往外找,结果为1。 函数使用了外部的数据,创建了闭包。

在这里插入图片描述
可以打印出结果,但是16行会报错,因为自动形成的闭包,会被销毁。

第二种情况
function eat(){
    var food = '鸡翅';
    return function(){
        console.log(food);
    }
}
var look = eat();
look(); // 鸡翅
look(); // 鸡翅

为什么能访问到food?
上面的示例中,照理说 eat 调用完毕 food 就应该被销毁掉,但是我们向外部返回了 eat 内部的匿名函数,匿名函数中引用了 food,所以垃圾回收器不会对其进行回收,所以在外面调用这个匿名函数时,仍然能够打印出food的值。

垃圾回收器只会回收没有被引用到的变量,但是一旦一个变量还被引用着的,垃圾回收器就不会回收此变量。

至此,闭包的优点也就体现出来了:

  • 通过闭包可以让外部环境访问到函数内部的局部变量。
  • 通过闭包可以让局部变量持续保存下来,不随着它的上下文环境一起销毁。
经典问题
for (var i = 1; i <= 3; i++) {
    setTimeout(function () {
        console.log(i);
    }, 1000);
}
// 4 4 4

循环中setTimeout访问了它的外部变量,形成闭包。三个timeout访问的是同一个变量。一秒后,i已经为4。
解决:
1.将i作为立即执行函数的参数传递,访问自己作用域内变量,不创建闭包。

for (var i = 1; i <= 3; i++) {
    (function (index) {
        setTimeout(function () {
            console.log(index);
        }, 1000);
    })(i)
}
// 1 2 3

2.利用es6语法,生成块级作用域,每次循环都有一个新的i,即使有闭包也没问题,因为保存的是不同的i。

for (let i = 1; i <= 3; i++) {
    setTimeout(function () {
        console.log(i);
    }, 1000);
}
// 1 2 3
闭包的面试题

闭包是什么?闭包的应用场景有哪些?怎么销毁闭包?

  • 闭包是一个封闭的空间,里面存储了在其他地方会引用到的该作用域的值,在 JavaScript 中是通过作用域链来实现的闭包。
  • 只要在函数中使用了外部的数据,就创建了闭包,这种情况下所创建的闭包,我们在编码时是不需要去关心的。
  • 我们还可以通过一些手段手动创建闭包,从而让外部环境访问到函数内部的局部变量,让局部变量持续保存下来,不随着它的上下文环境一起销毁。

场景:使用闭包可以解决一个全局变量污染的问题。

销毁:如果是自动产生的闭包,我们无需操心闭包的销毁,而如果是手动创建的闭包,可以把被引用的变量设置为 null,即手动清除变量,这样下次 JavaScript 垃圾回收器在进行垃圾回收时,发现此变量已经没有任何引用了,就会把设为 null 的量给回收了。

对闭包不同的定义

(助力于更好理解闭包)

MDN的定义

闭包是指那些能够访问自由变量的函数。

那么什么是自由变量呢?

指在函数中使用的,但既不是函数参数也不是函数的局部变量的变量。

JavaScript权威指南

从技术的角度讲,所有的JavaScript函数都是闭包

ECMAScript

1.从理论角度:

所有的函数。因为它们都在创建的时候就将上层上下文的数据保存起来了。哪怕是简单的全局变量也是如此,因为函数中访问全局变量就相当于是在访问自由变量,这个时候使用最外层的作用域。

2.从实践角度:以下函数才算是闭包:

1.即使创建它的上下文已经销毁,它仍然存在(比如,内部函数从父函数中返回)
2.在代码中引用了自由变量

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值