闭包:是指语法域位于某个特定的区域,具有持续参照(读写)位于该区域内自身范围之外的执行域上的非持久型变量值能力的段落。这些外部执行域的非持久型变量神奇地保留它们在闭包最初定义(或创建)时的值(深连结)。简单来说,闭包就是在另一个作用域中保存了一份它从上一级函数或作用域取得的变量(键值对),而这些键值对是不会随上一级函数的执行完成而销毁。周爱民说得更清楚,闭包就是“属性表”,闭包就是一个数据块,闭包就是一个存放着“Name=Value”的对照表。就这么简单。但是,必须强调,闭包是一个运行期概念。
闭包的特点:
1:作为一个函数变量的一个引用,当函数返回时,其处于激活状态。
2:一个闭包就是当一个函数返回时,一个没有释放资源的栈区。
简单的说,javascript允许使用内部函数---即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。
解决办法:
现在比较让人认同的闭包实现有如下三种:
1:
with
(obj){
//这里是对象闭包
}
|
2:
(
function
(){
//函数闭包
})()
|
try
{
//...
}
catch
(e) {
//catch闭包 但IE里不行
}
|
例子如下:三个<li>节点弹出相应的参数
<ul>
<li id=
"a1"
>aa</li>
<li id=
"a2"
>aa</li>
<li id=
"a3"
>aa</li>
</ul>
|
<script type=
"text/javascript"
>
for
(
var
i=1; i < 4; i++){
var
id = document.getElementById(
"a"
+ i);
id.onclick =
function
(){
alert(i);
//现在都是返回4
}
}
</script>
例子解决方案:
1:使用函数闭包。
var
lists = document.getElementsByTagName(
"li"
);
for
(
var
i=0,l=lists.length; i < l; i++){
lists[i].onclick = (
function
(i){
//保存于外部函函数
return
function
(){
alert(i);
}
})(i);
}
|
var
lists = document.getElementsByTagName(
"li"
);
for
(
var
i=0,l=lists.length; i < l; i++){
lists[i].onclick =
new
function
(){
var
t = i;
return
function
(){
alert(t+1)
}
}
}
|
2:利用事件代理
var
ul = document.getElementsByTagName(
"ul"
)[0];
ul.onclick =
function
(){
var
e = arguments[0] || window.event,
target = e.srcElement ? e.srcElement : e.target;
if
(target.nodeName.toLowerCase() ==
"li"
){
alert(target.id.slice(-1))
}
}
|
3:将暂时变量保留于元素节点上。
var
lists = document.getElementsByTagName(
"li"
);
for
(
var
i=0,t=0,el; el = list[i++];){
el.i = t++
el.onclick =
function
(){
alert(
this
.i)
}
}
|
4:使用with语句造成的对象闭包。
var
els = document.getElementsByTagName(
"li"
)
for
(
var
i=0,n=els.length;i<n;i++){
with
({i:i})
els[i].onclick =
function
() { alert(
this
.innerHTML+i) };
}
|
5:使用try...catch语句构造的异常闭包:
var
lists = document.getElementsByTagName(
"li"
);
for
(
var
i=0,l=lists.length; i < l; i++){
try
{
throw
i;
}
catch
(i){
lists[i].onclick =
function
(){
alert(i)
}
}
}
|