闭包,有人说它是一种设计理念,有人说全部的函数都是闭包。到底什么是闭包?这个问题在面试是时候常常都会被问,不少小白一听就懵逼了,不知道如何回答好。javascript
这个问题也有不少朋友在公众号给李老师留言了,问题表达方式不同,都是终归到一点,就是对闭包没有很清晰的理解。你们常常去网上找相关资料,可是对闭包的说法都是各类各样的,让你们对闭包的定义没有一个概念。
更多网页前端开发教程,行业资讯,面试技巧,欢迎关注前端开发学习公众号:网页前端开发学习
今天咱们就来一块儿讲讲什么是闭包,帮助你们理解,今天的内容能够直接收藏起来。方便之后看。前端
什么是闭包(Closure)
简单讲,闭包就是指有权访问另外一个函数做用域中的变量的函数。
MDN 上面这么说:闭包是一种特殊的对象。
它由两部分构成:函数,以及建立该函数的环境。环境由闭包建立时在做用域中的任何局部变量组成。
这种官方的概念是比较难理解的,在面试的时候说出来也不是很专业,由于没办法有个具体的逻辑。
我我的认为,理解闭包的关键在于:外部函数调用以后其变量对象本应该被销毁,但闭包的存在使咱们仍然能够访问外部函数的变量对象,这就是闭包的重要概念。
产生一个闭包
建立闭包最多见方式,就是在一个函数内部建立另外一个函数。下面例子中的 closure 就是一个闭包:
闭包的做用域链包含着它本身的做用域,以及包含它的函数的做用域和全局做用域。
闭包的注意事项
.一般,函数的做用域及其全部变量都会在函数执行结束后被销毁。可是,在建立了一个闭包之后,这个函数的做用域就会一直保存到闭包不存在为止。
从上述代码能够看到add5 和 add10 都是闭包。它们共享相同的函数定义,可是保存了不一样的环境。在 add5 的环境中,x 为 5。而在 add10 中,x 则为 10。最后经过 null 释放了 add5 和 add10 对闭包的引用。
在javascript中,若是一个对象再也不被引用,那么这个对象就会被垃圾回收机制回收;
若是两个对象互相引用,而再也不被第3者所引用,那么这两个互相引用的对象也会被回收。
闭包只能取得包含函数中任何变量的最后一个值
你们看一下上面这个代码,arr数组中包含了10个匿名函数,每一个匿名函数都能访问外部函数的变量i,那么i是多少呢?
当arrFunc执行完毕后,其做用域被销毁,但它的变量对象仍保存在内存中,得以被匿名访问,这时i的值为10。
要想保存在循环过程当中每个i的值,须要在匿名函数外部再套用一个匿名函数,在这个匿名函数中定义另外一个变量而且当即执行来保存i的值。
这时最内部的匿名函数访问的是num的值,因此数组中10个匿名函数的返回值就是1-10。
闭包中的this对象
在上面这段代码中,obj.getName()()其实是在全局做用域中调用了匿名函数,this指向了window。
这里要理解函数名与函数功能是分割开的,不要认为函数在哪里,其内部的this就指向哪里。
window才是匿名函数功能执行的环境。
若是想使this指向外部函数的执行环境,能够这样改写:
在闭包中,arguments与this也有相同的问题。下面的状况也要注意:
obj.getName();这时getName()是在对象obj的环境中执行的,因此this指向obj。
(obj.getName = obj.getName)赋值语句返回的是等号右边的值,在全局做用域中返回,因此(obj.getName = obj.getName)();的this指向全局。要把函数名和函数功能分割开来。
内存泄漏
闭包会引用包含函数的整个变量对象,若是闭包的做用域链中保存着一个HTML元素,那么就意味着该元素没法被销毁。因此咱们有必要在对这个元素操做完以后主动销毁。
函数内部的定时器
当函数内部的定时器引用了外部函数的变量对象时,该变量对象不会被销毁。
闭包的应用
应用闭包的主要场合是:设计私有的方法和变量。
任何在函数中定义的变量,均可以认为是私有变量,由于不能在函数外部访问这些变量。私有变量包括函数的参数、局部变量和函数内定义的其余函数。
把有权访问私有变量的公有方法称为特权方法(privileged method)。
在这里,咱们须要理解两个概念:
模块模式(The Module Pattern):为单例建立私有变量和方法。
单例(singleton):指的是只有一个实例的对象。JavaScript 通常以对象字面量的方式来建立一个单例对象。
上面是普通模式建立的单例,下面使用模块模式建立单例:
匿名函数最大的用途是建立闭包,而且还能够构建命名空间,以减小全局变量的使用。从而使用闭包模块化代码,减小全局变量的污染。
在这段代码中函数 addEvent 和 removeEvent 都是局部变量,但咱们能够经过全局变量 objEvent 使用它,这就大大减小了全局变量的使用,加强了网页的安全性。
运用闭包的关键
- 闭包引用外部函数变量对象中的值;
- 在外部函数的外部调用闭包。
闭包的缺陷
- 闭包的缺点就是常驻内存会增大内存使用量,而且使用不当很容易形成内存泄露。
- 若是不是由于某些特殊任务而须要闭包,在没有必要的状况下,在其它函数中建立函数是不明智的,由于闭包对脚本性能具备负面影响,包括处理速度和内存消耗。
最后 来一道有关闭包的面试题
下面代码中,标记 ? 的地方输出分别是什么?
你们结合今天讲解的内容,思考一下答案,你们能够把答案发到留意上吧。
好了,今天的讲解就那么多,若是你还有什么前端问题想提问的,或者你想李老师下次给你们讲什么内容,能够直接关注前端学习公众号:
【网页前端开发学习】留意提问,说不定下次文章就会讲解了。
若是你以为这篇文章对你有帮助,请转发点赞支持一下!