关于闭包的知识,首先来看一段代码:
function f1(){
var n = 10;
function f2(){
alert(n);
}
return f2;
}
var result = f1();
result();
上述代码中的函数可以理解为是一个闭包。f2可以访问f1的所有变量,反过来则不成立。即子对象可以访问父对象的所有变量,反过来不成立。
1. 关于闭包的定义:
闭包就是能够读取其它函数内部变量的函数。
在js中,只有函数内部的子函数才能读取局部函数,所以可以理解为“闭包是定义在函数内部的函数”。
2. 闭包的用处:
(1). 可以读取其它函数内部的变量
(2). 让这些变量始终保存在内存中
关于第(1)点,不多加解释。
关于第(2)点,因为f1是f2的父函数,f2被赋给一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制回收。
3. 闭包就是一个函数可以引用另一个函数的变量,因为变量被引用,所以不会被回收,因此可以用来封装一个私有变量。但不必要的闭包会增加内存的消耗。
4. 循环与闭包
先看下面这段代码:
function f1(){
var arr = [];
for(var i = 0;i < 10;i++){
arr[i] = function(){
return arr[i];
}
}
return arr;
}
var result = f1();
result[0] (); //10
result[9] (); //10
f1函数执行后,得到的是result数组。
数组中是十个未执行的函数function(){return arr[i]},当执行到result[9] ()时,变量i的值应该是函数在定义时i的取值,i=10时循环停止,所以i的取值为10,函数调用返回值也是10。
闭包的应用
(1). 用闭包实现点击li弹出li对应的序号
<ul class="ul">
<li>我是第一个li</li>
<li>我是第二个li</li>
<li>我是第三个li</li>
<li>我是第四个li</li>
<li>我是第五个li</li>
</ul>
<script>
function A(){
var oUl = document.getElementsByClassName("ul")[0];
var oLi = oUl.getElementsByTagName("li");
for(var i = 0;i < oLi.length;i++){
(function(i){
oLi[i].onclick = function(){
alert(i);
}
})(i);
}
}
A();
</script>
(2). 用闭包实现一个定时器
<script>
for(var i = 0;i < 10;i++){
(function(i){
setTimeout(function(){
console.log(i);
},i*1000);
})(i);
}
</script>
闭包的应用:上述两个问题,实现点击li弹出相对应的序号和使用闭包实现一个计时器,是前端面试中最常见的闭包问题。
对于学习js中的闭包,这两个应用问题是必须掌握的,