「1.闭包函数」
简称“闭包”,指的是有权访问另一个函数作用域内的变量(局部变量)的函数。
即函数定义和函表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。
也就是说,内部函数会在外部函数返回后被执行。而当这个内部函数执行时,它仍然必需访问其外部函数的局部变量、参数以及其他内部函数。这些局部变量、参数和函数声明(最初时)的值是外部函数返回时的值,但也会受到内部函数的影响。
「2.闭包函数的作用」
- 可以在函数外部读取函数内部的变量
- 可以让变量的值始终保持在内存中
注意:由于闭包会使函数中的变量一直保存在内存中,内存消耗很大,所以闭包的滥用可能会降低程序的处理速度,造成内存消耗等问题。
「3.闭包的常见创建方式」
就是在一个函数内部创建另一个函数,通过另一个函数访问这个函数的局部变量可以在函数外部读取函数内部的变量
在Javascript中闭包的创建过程,如以下程序所示。
function a(){
var i=0;
function b(){
alert(++i);
}
return b;
}
var c=a();
c();
「4.代码解释」
这段代码有两个特点:
1、函数b嵌套在函数a内部;
2、函数a返回函数b。
这样在执行完var c=a( )后,变量c实际上是指向了函数b,再执行c( )后就会弹出一个窗口显示i的值(第一次为1)。这段代码其实就创建了一个闭包,这是因为函数a外的变量c引用了函数a内的函数b。也就是说,当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。因为函数a被b引用,b又被a外的c引用,这就是为什么函数a执行后不会被回收的原因。
「5.作用」
简而言之,闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。
在上面的例子中,由于闭包的存在使得函数a返回后,a中的i始终存在,这样每次执行c(),i都是自加1后alert出i的值。
那么我们来想象另一种情况,如果a返回的不是函数b,情况就完全不同了。因为a执行完后,b没有被返回给a的外界,只是被a所引用,而此时a也只会被b引 用,因此函数a和b互相引用但又不被外界打扰(被外界引用),函数a和b就会被回收。
「6.运行机制」
function fun1() {
var a = 1;
function fun2() {
console.log(a);
}
return fun2;
}
var fn = fun1();
fn();//形成闭包,从外部获取内部作用域的信息。
(1)编译阶段,变量和函数被声明,作用域就确定下来。
(2)运行函数fun1(),创建fun1()函数的执行上下文,内部存储fun1()中所有的变量函数的信息。
(3)函数fun1()执行完之后,把fun2的引用赋值给外部变量fn,要明确的是此时fn的指针指向的是fun2,此时fn位于全局作用域,fun2位于函数作用域,所以可以看见fn位于fun1() 作用域之外,但是访问到了fun1()的内部变量。
(4)fn在全局被执行,内部代码console.log(a)向作用域请求获取a变量,在本级的作用域没有找到,就向上父级作用域一层一层找父亲(找爸爸)。在fun1()找到了a变量,返回给console.log所以打印出来了1。
「7.优缺点」
优点
- 保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突即属性私有化
- 在内存中维持一个变量,可以做缓存(但使用多了同时也是一项缺点,消耗内存)
- 匿名自执行函数可以减少内存消耗
缺点
- 其中一点上面已经有体现了,就是被引用的私有变量不能被销毁,增大了内存消耗,造成内存泄漏,解决方法是可以在使用完变量后手动为它赋值为null;
- 其次由于闭包涉及跨域访问,所以会导致性能损失,我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响