深入解析 闭包
什么是闭包?
-
在 JavaScript 语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。
-
闭包就相当于在函数内部和函数外部连接起来的桥梁。
-
在函数内部定义的函数,总是可以访问其所在的外部函数中声明的参数和变量。
下面代码将更好的帮助我们理解
function fn1(){
var num = 100;
function fn2(){
console.log(num);
}
return fn2;
}
var res = fn1(); // 这个返回值就是 fn1 函数的返回值,也就值 fn2 函数
res(); // 控制台就会输出 num 的值,也就是 输出 100
什么是闭包函数?
-
在 A 函数内部返回一个 B 函数,那么我们就说 B 函数是 A 函数的闭包函数。
-
例子:
function A(){ var num = 100; function B(){ console.log(num); } return B; } // 这里 我们就说 B 函数是 A 函数的闭包函数
闭包有什么作用呢?也就是说闭包有什么特点呢?
-
让外部去访问函数内部的私有变量成为了可能;
-
也就是让我们要访问的变量一致待在内存中,不会被销毁;
-
通俗的说:我们利用闭包可以实现数据的缓存;
-
当然,大量使用闭包也会导致内存泄漏的;
闭包为什么可以缓存数据呢?
一、这里要想深入理解闭包的缓存原理,我们就要回到函数的两个阶段了;
定义阶段:函数定义时,先在内存中开辟一个函数储存空间,把函数内部的代码存放在这个函数储存空间中,并把这个函数储存空间的地址赋值给函数名;
调用阶段:函数调用时,按照函数名中存储的地址,找到这个函数储存空间,再次开辟一个函数执行空间,把存储空间的代码复制一份到执行空间内部,在执行空间内部进行 形参赋值、预解析,然后执行代码,执行完代码后销毁执行空间。
二、闭包的原理就是让这个执行空间不销毁,那怎么让这个执行空间不销毁呢?
有两个必要条件:其一,执行空间内的那个函数内部必须返回一个复杂数据类型;其二,这个执行空间返回的复杂数据类型,在函数外部必须被引用着;当这两个条件同时满足时,执行空间就不会销毁。
形成闭包的条件:
-
在函数 A 内部直接或间接返回一个函数 B ;
-
在函数 B 内部使用着函数 A 的私有变量;
-
在函数 A 的外部有变量引用着函数 B ;
- 根据形成闭包的条件,我们不难看出,刚好满足了函数调用阶段,内存中的执行空间不销毁的条件,从而达到这个执行空间一直存在着,那么这个执行空间内部的变量也会存在;最终我们就可以一直使用这个执行空间中的变量了;也就实现的数据的缓存。
例子1: 直接在函数 A 内部返回一个函数 B
function A(){
var num = 100;
return function B(){
console.log(num);
}
}
var res = A();
res(); // 100
例子2:间接在函数 A 内部返回一个函数 B
function A(){
var num = 100;
return {
B: () => console.log(num);
}
}
var res = A();
res(); // 100
使用闭包注意的问题:
- 因为使用闭包会使函数中的变量一直保存在内存中,内存消耗性能很大,所以不要滥用闭包,不然会造成网页性能体验极差,解决的方法就是在退出函数之前,将不再使用的变量全部清空。
关键字:闭包 逆战