0%

js闭包_深入浅出

简单的对闭包做一个理解:

  • 闭包产生是:函数内嵌套函数;
  • 闭包函数在外面被调用,访问;
  • 闭包能使外部函数访问内部函数的变量;
  • 闭包可以保持对定义时的作用域的引用,使之不被销毁,就长生不老。

在看闭包之前我们还需要理解作用域

作用域主要分为两种:全局变量和局部变量。

全局变量&局部变量

局部变量:定义在函数内部,只能在函数中使用的变量,作用范围是从函数开始到结尾,即在{}里。
这里定义的a就是局部变量。

1
2
3
4
5
6
function myTest1(){
var a = 3;
return a;
}
console.log(a);//a is not defined
console.log( myTest1());//3

全局变量:常常定义在函数外部,拥有全局作用域,即在 JavaScript 代码的任何地方都可以访问

这里定义的b就是局部变量。

1
2
3
4
5
6
var b = 3;//全局变量
function myTest2(){
return b;
}
console.log(b);//3
console.log(myTest2());//3

从这里我们就可以知道,函数内部可以调用全局变量,但是函数外部无法读取函数内的局部变量

函数内部声明变量的时候,必须使用var命令去声明一个变量。如果不用的话,就会声明了一个全局变量

1
2
3
4
5
6
7
8
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

在这里我们cd都是在函数内部声明的,但是因为c使用了var,而d没有使用var声明,所以在外部能够使用d;也就是所谓的声明了一个全局变量


闭包

在理解了全局变量局部变量之后,我们先写一个简单的闭包实例给大家看看:

1
2
3
4
5
6
7
8
function myTest4(){
var i = 4;
return function(){
return i;
}
}
var func = myTest4();
console.log(func());//4

在这里我们是不是有点明白了呢:如果我们想用一个变量或者得到一个变量,但是我们又不想全局声明定义这个变量,到这的时候我们就可以通过闭包来调用函数内部的变量。

但是我们也应该知道闭包产生的值是一直保存在内存中的。这里通过一个例子给大家看看:

1
2
3
4
5
6
7
8
9
10
function myTest5(){
var i = 4;
return function(){
return i++;
}
}
var func = myTest5();
func();//4
func();//5
console.log(func());//6

这个例子就是说调用一次,然后i的值就变了一次并且会一直被保存,然后下次调用的时候就是上次保存的值了。

一些闭包实例:

/* 例子1 */

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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 */

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 */

1
2
3
4
5
6
7
8
var lis = document.getElementsByTagName("li");
for(var i=0;i<lis.length;i++){
(function(i){
lis[i].onclick = function(){
console.log(i);
};
})(i); //事件处理函数中闭包的写法
}

回收

由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE浏览器中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

一个简单的回收实例:

1
2
3
4
5
6
7
8
9
10
11
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

总结

  • 闭包的缺点就是常驻内存,闭包会使变量始终保存在内存中,如果使用不当会增大内存使用量,造成内存泄露。

  • 正常情况下外部函数是不能访问内部函数的变量的,但是可以利用闭包来实现对函数内部变量的访问。

  • 一般函数执行完毕后,局部活动对象就被销毁,内存中仅仅保存全局作用域。但闭包的情况不同!