一、什么是闭包?
先说概念:
闭包是指有权访问另一个函数作用域中变量的函数。
创建闭包的最常用的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域,将函数内部的变量和方法传递到外部。
二、关于闭包概念的理解
从概念中可以看出,要形成闭包有2个不可或缺的关键因素,分别是:
①1个函数 ②函数内部可以访问的变量
比如:
var num = 665;
function sayAlert(){
alert(num);
}
(在上述例子中,num就是1个变量,而sayAlert则是一个函数,在该函数中可以访问num这个变量。)
紧接着把这几句代码放到一个立即执行函数中,再return该函数,如下所示:
function say666() {
var num = 665;
function sayAlert() {
alert(num);
}
num++;
return sayAlert;
}
var sayAlert = say666();
sayAlert(); //执行结果为弹出666
在上述例子中,sayAlert函数和num变量就形成了闭包。
可以看出有两个问题:
一、为什么需要函数嵌套函数?
函数嵌套函数是为了让变量成为局部变量,比如在上述例子中num就成为了局部变量,如果不嵌套直接写在外面就成为了全局变量。
所以,函数套函数就是为了制造出一个局部变量。
二、为什么需要return函数?
return函数就是为了让这个函数可以被使用,在上述例子中return sayAlert就是为了让这个函数在外部可以被使用。
解决了上述两个问题后,又有一个问题出现了:
为什么要让变量成为局部变量呢?
我想这个问题有好几个答案,首先是局部变量可以一直被保存在内存中,不会被垃圾回收机制回收。还有就是可以通过闭包来隐藏一个变量,比如在上述例子中我们也完全可以让num成为一个全局变量,但是我又不想让num这个变量的值被任何人任意更改(不想让别人直接访问到这个变量),所以我们可以让它成为局部变量,并且暴露一个函数,让他人可以间接访问。
三、分享一个闭包使用案例
最后给大家分享一个闭包的使用案例,使用闭包让 4个li节点的onclick事件都能正确的弹出当前被点击的li索引:
<ul>
<li>index =0</li>
<li>index =1</li>
<li>index =2</li>
<li>index =3</li>
</ul>
<script>
var nodes=document.getElementsByTagName("li");
for(var i=0;i<nodes.length;i++){
nodes[i].onclick=(function(i){
return function(){
console.log(i)
}
})(i)
}
</script>
在上述例子中,return后的函数和变量i就形成了闭包,如果不使用闭包直接打印的话,那么不管点击哪个li打印出来的值都是4。
大家可以自行尝试。
四、一道面试题
function Foo(){
var i=0;
return function(){
document.write(i++);
}
}
var f1=Foo(),
f2=Foo();
f1();
f1();
f2();
上述代码,最后输出的结果是?
答案是:0,1,0
这道题就是使用了闭包,它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
这里的局部变量i,对f1()来说是全局变量,对f2()来说也是全局变量,但是f1()的i跟f2()的i又是相互独立相互不可见的,闭包被引用的变量不会被释放,f1()每执行一次,f1()的i就加1,f2()每次执行一次,f2()的i就加1,但是相互之间不影响,因此结果是010.
有任何问题欢迎在留言区指出和讨论(✿◕‿◕✿)