什么是闭包?
要理解什么是闭包,首先得知道什么是作用域,作用域分为全局作用域和局部作用域,而计算机语言的奇妙之处就在于局部作用域中可以访问全局变量,而全局作用域不能访问局部变量,如何解决这一问题?这就用到了闭包。
闭包:可以访问另外一个函数内部局部变量的函数叫做闭包
全局作用域:
<script type="text/javascript">
var n = 10
function fn(){
console.log(n)
}
fn()//10
</script>
局部作用域:
<script type="text/javascript">
function fn() {
var n = 10//函数内部声明变量的时候,一定要使用var命令。如果不用的话,实际上声明了一个全局变量!
}
console.log(n)//error
</script>
二、如何使用闭包
那当我们需要用到函数内的局部变量的时候怎么办呢?我们前面说过,正常的方法是行不通的,所以我们需要变通一下。
我们可以在函数内部再定义一个函数。
<script type="text/javascript">
function fn(){
var num = 10
function fun(){
console.log(num)
}
return fun
}
var f = fn()
f()
</script>
在fn函数里面定义了一个fun(),由于作用域链的的原因,fun的作用域可以访问到fn内部函数的变量,然后把fun return出去,在外面通过一个变量接收,就可以访问到函数变量的局部变量了。
在这个例子中fun就是闭包,简单理解就是可以访问其他函数内变量的函数就是闭包。
三、闭包的作用与影响
优点:闭包延伸了变量的作用范围
缺点:由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。但也有可能造成内存泄漏
四、面试题
先借用阮一峰老师写的两个例子
1、
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
console.log(object.getNameFunc()());//"The Window",无闭包产生
相当于
var f1 = object.getNameFunc
var f2 = f1()= return function(){
return this.name;
};
var f3 = f2()= return this.name;
console.log(f3);
getNameFunc: function() {//假设函数名为A
return function()/*假设函数名为B*/
{ return this.name; };
}
在函数B内调用函数A的this.name,而B函数属于匿名函数自调用,在匿名函数中this指向的是window,所以this.name = "The Window"
2、
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
console.log(object.getNameFunc()()); //"My Object"
3、循环遍历与监听
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<button type="button">测试1</button>
<button type="button">测试2</button>
<button type="button">测试3</button>
<script type="text/javascript">
var btns = document.getElementsByTagName('button')
//遍历+监听:因为监听是回调函数,是循环完成后才会调用,所以弹出的永远是第四个
// var length = btns.length
// for(var i=0;i<length;i++){
// var btn = btns[i]
// btn.onclick = function(){
// alert("第"+(i+1)+'个')
// }
// }
//解决方法一、
// var length = btns.length
// for(var i=0;i<length;i++){
// var btn = btns[i]
// btn.index = i
// btn.onclick = function(){
// alert("第"+(this.index+1)+'个')
// }
// }
//解决方法二、闭包的方式解决
for(var i=0;i<btns.length;i++){
//利用for循环创建了4个立即执行函数
//立即执行函数也成为小闭包,因为立即执行函数里面的任何一个函数都可以使用他的i这个变量
(function(i){
//console.log(i)
btns[i].onclick=function(){
console.log(i)
}
})(i)
}
</script>
</body>
</html>