闭包意味着内层的函数可以引用存在于包围它的函数内的变量,即使外层函数的执行已经终止。
让我们先来看一个闭包的例子。
<script type="text/javascript">
function add(num){
return function(toAdd){
return num+toAdd; //代码①
}
}
var addFive = add(5); //此时addFive为function(toAdd){return num+toAdd;}
var count = addFive(3); //此时count为 num+toAdd
alert(count);//8
</script>
代码①是处于函数内层,不过它可以使用外层的变量num。
闭合还能解决另一个常见的Js问题,全局变量的影响。
通过自动执行匿名函数组合闭包,便可把原本属于全局的变量隐藏起来。看下面的例子:
<script type="text/javascript">
(function(){
var msg = "Hello";
window.onunload = function(){
alert(msg);//输出Hello
}
})()
//alert(msg);//出现未定义
</script>
在使用setTimeout时,我们经常也用上了闭包。
<html>
<head>
<title>demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript">
window.onload = function(){
var obj = document.getElementById("abc");
obj.style.border = "1px solid #000";
setTimeout(function(){
obj.style.color = "red";
},1000)
function DeAlert(msg , time){
setTimeout( function(){
alert(msg);
},time)
}
DeAlert("hello",2000);
}
</script>
</head>
<body>
<div id="abc">CssRain</div>
</body>
</html>
以这种方式使用setTimeout(),可以避免一些问题。
当然使用闭包 也会带来一些问题。如下代码所示:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript">
window.onload = function(){
var ul = document.getElementById("abc");
var li = document.getElementsByTagName("li");
for(var i=0;i<li.length;i++){
li[i].onclick = function(){
alert("你单击的是第"+i+"个li。");
}
}
}
</script>
</head>
<body>
<ul id="abc">
<li>AAA</li>
<li>BBB</li>
<li>CCC</li>
</ul>
</body>
</html>
单击li弹出的序号为 3 ,并不是正确的序号,它引用的值是最后一次的赋值。
我们可以使用下面代码来解决:
<script type="text/javascript">
window.onload = function(){
var ul = document.getElementById("abc");
var li = document.getElementsByTagName("li");
for(var i=0;i<li.length;i++){
(function(){ //使用一个自执行的匿名函数 来激发出作用域
var b = i ; //记住在这个作用域内的值
li[b].onclick = function(){ //使用刚才记住的值,变量b
alert("你单击的是第"+b+"个li。");
}
})()
}
}
</script>
通过使用闭包对作用域的控制,从而符合了我们的要求。
上面的代码可以分解为:
<script type="text/javascript">
window.onload = function(){
var ul = document.getElementById("abc");
var li = document.getElementsByTagName("li");
function a(){
var b = 0 ;
li[b].onclick = function(){
alert("你单击的是第"+b+"个li。");
}
}
function b(){
var b = 1 ;
li[b].onclick = function(){
alert("你单击的是第"+b+"个li。");
}
}
function c(){
var b = 2 ;
li[b].onclick = function(){
alert("你单击的是第"+b+"个li。");
}
}
a();
b();
c();
}
</script>
闭包的概念不容易掌握,我也是花了大量时间和精力才理解。
6,小结
笔记(2),(3),(4)讲解了 JavaScript中的几个重要的内容,包括引用,函数重载,作用域,上下文对象和闭包。
引用的关键内容: 指针,数组引用,字符串引用,区别,传值,传址。
函数重载的关键内容: 参数的数量,参数的类型,arguments,伪数组,typeof,constructor,区别-字符串和对象。
作用域的关键内容: 函数划分,全局作用域,全局对象,window对象的属性,局部作用域,显式声明,隐式声明。
上下文对象的关键内容: this变量,call,apply,参数区别,数组。
闭包的关键内容: 内层函数,外层函数,变量,setTimeout,闭包问题,最后一次的赋值,闭包和作用域。