怎么理解JavaScript中的闭包


前言

本文是作者学习阶段对闭包的理解,主要介绍了闭包的基础知识点和对知识点的理解。

本文排版约定

Q — 问题
A — 回答


关于闭包

1.是什么?

《你不知道的JavaScript》里的定义为:

当函数可以记住并访问所在的词法作用域时,就产生了闭包。即使函数是在当前词法作用域之外执行。

2.优缺点?

优点

  1. 实现封装,属性私有化。 在自己的函数作用域内,实现内部成员变量,提供function接口。
  2. 保护作用域不被释放,成员变量被缓存起来具有记忆性。
  3. 模块开发,防止污染全局变量。

缺点

  1. 闭包会导致作用域链不释放,造成内存泄漏

3.怎么用?(以累加器举例)

引入变量的生命周期

code - 1:

var x = 0;
function fn1() {
    return ++x;
}
console.log(fn1());
console.log(fn1());
//输出:
//1
//2

code - 2:

function fn2() {
    var x = 0;
    return ++x;
}
console.log(fn2());
console.log(fn2());
//输出:
//1
//1

Q1:为什么输出的结果不同?
A1:我们知道JS是运行在浏览器,浏览器引擎有垃圾回收器。
fn1()和fn2()在完成自己的"任务"之后,都被回收释放了。code -1 中的变量x为全局变量,缓存仍然存在,不会被回收;但code-2中的变量x定义在fn2()中,为局部变量,所以x一并被回收。
code-2代码中的fn2()被重复调用时,x一直在被重复定义并赋值为0,没有被缓存下来。

Q2:code-1实现了累加计数,为什么还要使用闭包这个概念,换言之code-1有什么缺陷?
A2:我们知道,在一个项目中需要使用到很多变量名,code-1将变量定义在全局范围内(这没有错),造成了全局变量的污染;并且变量x不常使用的话,闲置在内存中,浪费内存空间。

于是我们用上闭包

code - 2.1:

//这里用到了自执行函数(function(){})()
var add = (function () {
    var x = 0;
    function doAdd() {return x += 1;}
    return doAdd;
})();
console.log(add());
console.log(add());
console.log(add());
//输出:
//1
//2
//3 

此时,变量x就只作用于匿名函数所在的那个作用域,不会对全局变量造成污染。当code - 2.1执行完第一个console.log(add());垃圾回收器并不会对add进行回收释放,因为doAdd函数已经被保存到外部,作用域仍然存在。
总而言之累加器受匿名函数的作用域保护,只能通过 add 方法修改。

这也解释了闭包的缺点,如果写了太多的闭包,就会占用大量的内存,从而导致内存泄漏。闭包需要手动内存释放,让引用 add = null;即可


总结

  • 通过案例学过 java 的朋友就不难想到 闭包和"类"非常的相似

    定义在函数内部的变量 -> 类中的成员变量
    定义在函数中的方法 -> 类中的成员方法
    好比对象,通过封装来让变量私有化,提供函数来访问成员变量。

  • 最后,我理解得出闭包像是一种保护机制;闭包形成一个不销毁的栈环境,用来保护内部函数,成员属性不受外界的干扰。

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值