闭包:内层函数可以访问外层函数的变量,
当某个函数被调用时,会创建一个执行环境及相应的作用域链,然后用argument来和参数来初始化活动变量。
在作用域链中,外部的活动对象始终处于第二位,外部函数的外部函数处于第三位,直到作用域链的终点,也就是全局执行环境。
访问变量时,会从作用域链的前端开始访问。因为闭包,外部执行环境的作用域链会在函数执行后立即销毁,但是活动变量会被保存。
闭包的作用:
1.匿名自执行函数,有的函数只执行一次
2.缓存,避免调用一个处理过程很长的函数对象
3.实现封装
4.实现对象
5模仿私有变量、块级作用域
缺点:由于会保存活动变量,会导致内存泄露问题
function assignHandler(){
var element = document.getElementById("some");
bar id = element.id;
element.onclick = function(){
alert(id);
}
element.id;
}
闭包常见应用场景:
<body>
<ul><li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
/* var oUl = document.getElementsByTagName("ul")[0];
var aLi = oUl.getElementsByTagName("li");
for(var i = 0; i<aLi.length; i++){
aLi[i].onclick = function(num){
return function(){
alert("i="+i+",num="+num);
}
}(i);
}*/
//原始的,最爱犯的错,每次创建一个function,始终保存着外部活动对象,而他们引用的是同一个变量i,所以将每个函数的i都将是5
function createFunction1(){
var result= new Array();
for(var i=0; i<5; i++){
result[i] = function(){
return i;
};
}
return result;
}
alert(createFunction1()[0]());
//创建了新的域,但仍然输出i,因为原型链中,每次创建一个function,始终保存着外部活动对象,而他们引用的是同一个变量i,此时虽然已经创建了新的域,但是i是外部函数的变量(此时已经 = 4),每次创建的function仍然会引用最后的i值
function createFunction2(){
var result= new Array();
for(var i=0; i<4; i++){
result[i] = function(){
return function(){
return i;
};
}();
}
return result;
}
alert(createFunction2()[0]());
//每次都会创建一个function与本身function对应的一个num,因为值传递,所以每一次创建function的时候,传入的参数i(传给num),而这个参数num是i的副本,在函数创建的时候i的值分别为0,1,2,传入的num自然也就是0,1,2。而因为参数的作用域为函数内部,所以每次都会创建一个function与本身function对应的一个num(0,1,2),且因为num是一个局部变量,所以它的值不会被下一个函数的值影响,此时虽然每次创建一个function,始终保存着外部活动对象,但是它不影响局部变量num的值
function createFunction3(){
var result= new Array();
for(var i=0; i<3; i++){
result[i] = function(num){
return function(){
return num;
};
}(i);
}
return result;
}
alert(createFunction3()[0]());
//总结也就是有多个num,只有一个i,所以num每次不同,而i每次都相同
</script>
</body>