闭包
闭包是JavaScript语言的一大特点,主要应用场合为:设计私有的方法和变量。
什么是闭包函数?
理解闭包前,需要先理解 全局作用域 和 局部作用域 的区别。函数内部可以访问全局作用域下定义的全局变量,而函数外部却无法访问到函数内部定义(局部作用域)的局部变量。
- 概念: 闭包(closure)是定义在一个外部函数内部,并且能够访问外部函数中变量的函数。
- 原理: 作用域链
创建闭包的常见方式,就是在一个函数内部创建另一个函数并返回:
function fun(num){
return function (){
return num;
}
}
var end = fun(100);
console.log(end()); // 100
上述案例中,num 是fun函数内部的变量,本来只能fun函数内部使用,但是返回的函数也有权限访问num。所以在函数外部通过调用返回的函数即可得到函数内部的变量
function out (){
var n = 1;
return function (){
return n++;
}
}
var fn = out();
console.log(fn()) //1
console.log(fn()) //2
console.log(fn()) //3
注意:由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。
闭包三个特性
- 函数嵌套函数
- 函数内部可以引用外部的参数和变量
- 参数和变量不会被垃圾回收机制回收
闭包的缺点
闭包的缺点就是常驻内存,会增大内存使用量,使用不当很容易造成内存泄漏。 一般函数执行完毕后,局部活动对象就会被销毁,内存中仅仅保存全局作用域。但闭包的情况不同。
使用闭包的好处
1. 希望一个局部变量长期驻扎在内存中
局部变量长期驻扎内存
function out (){
var n = 1;
return function (){
return n++;
}
}
var fn = out();
console.log(fn()) //1
console.log(fn()) //2
console.log(fn()) //3
在循环中直接找到对应的元素的索引
例1:
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
var lis = document.getElementsByTagName("li");
for(var i=0;i<lis.length;i++){
(function(i){
lis[i].onclick = function(){
alert(i); //0 1 2
}
})(i)
}
例2:
for(var i=0;i<10;i++){
setTimeout(function(){
console.log(i); //10
}, 1000)
}
2. 避免全局变量的污染
当我们声明一个函数的时候其实就相当于创建一个全局变量 上一个例子中总共占有2个全局变量。
函数表达式 函数自调用:
(function(){
})()
var out = (function(){
var n1 = 1;
var n2 = 100;
return function(){
n1++;
n2--;
return n1+n2;
}
})();
console.log(out()); // 101
console.log(out()); // 101
3. 私有成员的存在
模块化代码
var aa=(function(){
var a=10;
function aaa(){
a++;
alert(a);
}
function bbb(){
a+=10;
alert(a);
}
return {
a:aaa,
b:bbb
}
})()
console.log(aa.a()); //11
console.log(aa.b()); //21