概述:
函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起构成闭包(closure)。也就是说,闭包可以让你从内部函数访问外部函数作用域。在 JavaScript 中,每当函数被创建,就会在函数生成时,同时自动生成闭包。
说白了,就是有函数的地方,就存在closure,无论你是否看得见。
特点:
1.让外部访问函数内部变量成为可能;
2.局部变量会常驻在内存中;
3.可以避免使用全局变量,防止全局变量污染;
4.会造成内存泄漏(有一块内存空间被长期占用,而不被释放)
案例:
经典案例:
要求:点击当前li弹出对应内容
<ul>
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
</ul>
<script>
var lis = document.getElementsByTagName("li");
for(var i = 0;i < lis.length;i++){
lis[i].onclick = function(){
console.log(i)
}
}
</script>
解析:
for循环是同步加载,点击事件是异步加载,异步加载是等同步加载完成后开始,所以当i=10的时候,点击事件开始加载执行 ,生成自己的AO,但自己的AO里没有i, 所以根据作用域链,往下找,从GO中取值,所以输出一直是10
解决方案:
<script>
var lis = document.getElementsByTagName("li");
for(var i = 0;i < lis.length;i++){
(function(i){
lis[i].onclick = function(){
console.log(i)
}
})(i)
}
</script>
解析:在函数内部加个闭包,一个立即执行函数,每次点击,都会生成一个自己的AO,里面有i,不用去GO里取值,所以点击当前li出来对应的值
案例1:
function makeFunc() {
var name = "chrome";
function displayName() {
alert(name);
}
return displayName; //注意这里
}
var myFunc = makeFunc();
myFunc();
解析:
内部函数 displayName() 在执行前,从外部函数返回。
第一眼看上去,也许不能直观地看出这段代码能够正常运行。
在一些编程语言中,一个函数中的局部变量仅存在于此函数的执行期间。
一旦 makeFunc() 执行完毕,你可能会认为 name 变量将不能再被访问。
然而,因为代码仍按预期运行,所以在 JavaScript 中情况显然与此不同。
原因在于,JavaScript中的函数会形成了闭包。
闭包是由函数以及声明该函数的词法环境组合而成的。
该环境包含了这个闭包创建时作用域内的任何局部变量。在本例子中,myFunc 是执行 makeFunc 时创建的 displayName 函数实例的引用。displayName 的实例维持了一个对它的词法环境(变量 name 存在于其中)的引用。因此,当 myFunc 被调用时,变量 name 仍然可用,其值 chrome就被传递到alert中