什么是闭包?
官方”的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
相信很少有人能直接看懂这句话,因为他描述的太学术。其实这句话通俗的来说就是:Javascript中所有的function都是一个闭包。不过一般来说,嵌套的function所产生的闭包更为强大,也是大部分时候我们所谓的“闭包”。看下面这段代码:
function a() {
var i = 0;
function b() { alert(++i); }
return b;
}
var c = a();
c();
这段代码有两个特点:
1、函数b嵌套在函数a内部;
2、函数a返回函数b
在执行完var c=a()后,变量c实际上是指向了函数b,再执行c()后就会弹出一个窗口显示i的值(第一次为1)。这段代码其实就创建了一个闭包,为什么?因为函数a外的变量c引用了函数a内的函数b,就是说:
当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。
产生闭包的条件:
函数嵌套
内部函数引用了外部函数的数据(变量/函数)
闭包的优点
(1)可以读取函数内部的变量。
变量的作用域无非就是两种:全局变量和局部变量;
S语言的特殊之处,就在于函数内部可以直接读取全局变量;
另一方面,函数外部自然无法读取函数内的局部变量。
(2)让这些变量的值始终保存在内存中,作用域空间不销毁,相对于局部变量来说,浪费了内存。
(3)保护私有变量
闭包的缺点:
常驻内存会增大内存的使用量
使用不当会造成内存泄露
闭包会在父函数外部,改变父函数内部变量的值
闭包的形成环境:
(1)函数的嵌套
(2)内部函数使用外部函数中的变量
(3)将内部函数返回,在外部函数的外部,接收返回值,执行(相当于执行了内部函数)
闭包的应用场景
(1)函数作为返回值。
function box() {
var n = 1;
function cox() {
n++;
return n;
}
return cox;
}
// res 就是一个闭包 ,n像是一个全局变量
var res = box();
console.log(res()); // 2
console.log(res()); // 3
(2)循环中的事件,事件处理函数中使用了循环的每次的计数器。
<body>
<div id="box"></div>
<ul class="list">
<li>link1</li>
<li>link2</li>
</ul>
</body>
<script>
var ali = document.querySelectorAll(".list li");
for(var i=0;i<ali.length;i++){
ali[index].onclick = (function(index){
return function(){
console.log(index);
}
})(i);
}
</script>
(3)给某些系统默认的回调函数,传参。
function fn(a){
return function(){
console.log(a);
};
}
setTimeout(fn("world"), 1000);
(4)处理掉全局变量。
var f = (function(){
var a = "hello";
function fn(){
console.log(a + "world");
}
return fn;
})();
f();
Javascript的垃圾回收机制
在Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。因为函数a被b引用,b又被a外的c引用,这就是为什么函数a执行后不会被回收的原因。