由浅入深的对闭包进行剖析:
先简单的对闭包做一个理解:
概念:当内部函数被保存在外部时,将会产生闭包。
简单的来个闭包的小总结,方便理解下面介绍:
- 闭包产生是:函数内嵌套函数;
- 闭包函数在外面被调用,访问;
- 闭包能使外部函数访问内部函数的变量;
- 闭包可以保持对定义时的作用域的引用,使之不被销毁,就长生不老。
在看闭包之前我们还需要理解作用域。
作用域主要分为两种:全局变量和局部变量。
全局变量&局部变量
局部变量:定义在函数内部,只能在函数中使用的变量,作用范围是从函数开始到结尾,即在**{}**里。
这里定义的a
就是局部变量。
function myTest1(){
var a = 3;
return a;
}
console.log(a);//a is not defined
console.log( myTest1());//3
全局变量:常常定义在函数外部,拥有全局作用域,即在 JavaScript 代码的任何地方都可以访问
这里定义的b
就是局部变量。
var b = 3;//全局变量
function myTest2(){
return b;
}
console.log(b);//3
console.log(myTest2());//3
从这里我们就可以知道,函数内部可以调用全局变量,但是函数外部无法读取函数内的局部变量
函数内部声明变量的时候,必须使用var命令去声明一个变量。如果不用的话,就会声明了一个全局变量。
function myTest3(){
var c = 4;
d=3;
return c,d;
}
console.log( myTest3());//4,3
console.log(d);//3
console.log(c);//c is not defined
在这里我们c
和d
都是在函数内部声明的,但是因为c
使用了var
,而d
没有使用var
声明,所以在外部能够使用d
;也就是所谓的声明了一个全局变量
闭包
在理解了全局变量和局部变量之后,我们先写一个简单的闭包实例给大家看看:
function myTest4(){
var i = 4;
return function(){
return i;
}
}
var func = myTest4();
console.log(func());//4
在这里我们是不是有点明白了呢:如果我们想用一个变量或者得到一个变量,但是我们又不想全局声明定义这个变量,到这的时候我们就可以通过闭包来调用函数内部的变量。
但是我们也应该知道闭包产生的值是一直保存在内存中的。这里通过一个例子给大家看看:
function myTest5(){
var i = 4;
return function(){
return i++;
}
}
var func = myTest5();
func();//4
func();//5
console.log(func());//6
这个例子就是说调用一次,然后i
的值就变了一次并且会一直被保存,然后下次调用的时候就是上次保存的值了。
一些闭包实例:
/* 例子1 */
function outerFn(){
var i = 0;
function innerFn(){
i++;
console.log(i);
}
return innerFn;
}
var inner = outerFn(); //每次外部函数执行的时候,都会开辟一块内存空间,外部函数的地址不同,都会重新创建一个新的地址
inner(); //1
inner(); //2
inner(); //3
var inner2 = outerFn();
inner2(); //1
inner2(); //2
inner2(); //3
/* 例子2 */
function m1(){
var x = 1;
return function(){
console.log(++x);
}
}
m1()(); //2
m1()(); //2
m1()(); //2
var m2 = m1();
m2(); //2
m2(); //3
m2(); //4
/* 例子3 */
var lis = document.getElementsByTagName("li");
for(var i=0;i<lis.length;i++){
(function(i){
lis[i].onclick = function(){
console.log(i);
};
})(i); //事件处理函数中闭包的写法
}
回收
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE浏览器中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
一个简单的回收实例:
function myTest6(){
var i = 4;
return function(){
return i++;
}
}
var func = myTest5();
console.log(func());//4
func = null;//n被回收
var func = myTest5();
console.log(func());//4
总结:
从作用上:
**作用1:**隐藏变量,避免全局污染
**作用2:**可以读取函数内部的变量
同时闭包使用不当,优点就变成了缺点:
缺点1:导致变量不会被垃圾回收机制回收,造成内存消耗
缺点2:不恰当的使用闭包可能会造成内存泄漏的问题
基于hexo搭建的一个博客:https://nanxiangscholar.github.io/
欢迎访问!