我的博客
闭包的概念:有权访问另一个函数作用域中的变量的函数;一般情况就是在一个函数中包含另一个函数。
从官方定义我们知道闭包是一个函数,只不过这个函数有[特殊权限],可以访问到另一个函数的作用域。
因为我们知道函数作用域是独立的、封闭的,外部的执行环境是访问不了的,但是闭包具有这个能力和权限。
我们先来看一段普普通通的函数。
控制台输出结果:
1 2 3
再来看一段局部变量的代码:
控制台输出结果:
红色框是当前的这段局部变量代码。看得出,他并没有累加。
当我们调用时,局部变量b为0,然后b+=1
后返回一个值,然后,此时,因为全局变量不会消失,而局部变量在运行完后,他是会被JavaScript的运行机制处理掉的。
所以,当你调用第二次,他重新创建了变量b,然后,结果可想而知。
//闭包函数 function add3(){ var b= 0; return function(){ return b += 1; } }
最后,就看看我们的特殊权限。
我们将运算过程使用匿名函数包裹,此时,这个匿名函数在我们的主函数内,就相当于时主函数的儿子,既然是父子关系,自然你父亲对待你和对待其他孩子不一样。这就是里面的这个函数的特殊权限。
所以,他是有权限去访问到内部的b的,当我们调用这个函数,因为有子函数的存在,所以b这个对象不会消失。相当于后继有人,b就不会被机制回收。
所以,此时运行结果,也是1、2、3
。
随后,贴上三段代码,自行琢磨:
//普通函数(全局变量) var a = 0; function add(){ return a += 1; } //调用3次函数 for (var i = 0; i <3; i++){ console.log(add()); } //普通函数(局部变量) function add2(){ var b= 0; return b += 1; } //调用3次函数 for (var i = 0; i <3; i++){ console.log(add2()); } //闭包函数 function add3(){ var b= 0; return function(){ return b += 1; } } //调用请自行琢磨
闭包的实现原理,其实是利用了作用域链的特性,我们都知道作用域链就是在当前执行环境下访问某个变量时,如果不存在就一直向外层寻找,最终寻找到最外层也就是全局作用域,这样就形成了一个链条。
至于什么是作用域链,你可以将其看成函数嵌套。
访问某个变量时,如果不存在就一直向外层寻找。
作用1: 隐藏变量,避免全局污染
作用2: 可以读取函数内部的变量
同时闭包使用不当,优点就变成了缺点:
缺点1: 导致变量不会被垃圾回收机制回收,造成内存消耗
缺点2: 不恰当的使用闭包可能会造成内存泄漏的问题
为什么使用闭包时变量不会被垃圾回收机制收销毁呢?
这里需要了解一下JS
垃圾回收机制:
JS
规定在一个函数作用域内,程序执行完以后变量就会被销毁,这样可节省内存。使用闭包时,按照作用域链的特点,闭包(函数)外面的变量不会被销毁,因为函数会一直被调用,所以一直存在,如果闭包使用过多会造成内存销毁。
所以说,我们要通晓一个事物的原理,并且最优化的使用它。知己知彼,方可百战百胜。