深入理解JavaScript闭包
2017-04-17 本文已影响0人
LeeYee11
作用域
- 变量加var修饰即为局部变量,否则为全局变量
function foo(){
a=1
var b=1;
}
foo();
console.log(a);//1
console.log(b);//ReferenceError: b is not defined
- 和函数内部的作用域不同,语句块内的作用域相当于全局
i=999;//全局变量
function foo(){
var i=233;//局部变量
console.log(i);
}
foo();//233
console.log(i);//999
for(var i=0;i<10;i++){ //此处的i为全局变量i
console.log(i);//1 2 3 4 5 6 7 8 9
}
console.log(i);//10
- 函数内部可以读取到函数外部的变量,但是函数外部的变量不能读取到函数内部的变量
var a=1;
function foo(){
a=2;
var b=2;
}
foo();
console.log(a);//2
console.log(b);//ReferenceError: b is not defined
- 函数内部的函数也可能读到函数内部的变量
function foo(){
var a=1;
function bar(){
console.log(a);
}
bar();
}
foo(); //1
- 因此可以用函数内部的函数作为返回值来获取函数内部的值
function foo(){
var a=2;
function bar(){
console.log(a);
}
return bar;
}
var getResult=foo();
getResult();
闭包
- 闭包可以用于获取函数内的局部变量
function foo(){
var i=1;
function getI(){
return i;
}
return getI;
}
console.log(i);//undefined
var GI=foo();
var i=GI();
console.log(i);//i
- 闭包可以用于缓存变量
function foo(){
var i=1;
function getI(){
return ++i;
}
return getI;
}
var GI=foo();
var i=GI();
console.log(i);//2
i=GI();
console.log(i);//3
//说明此处依然是调用的foo的缓存
//因为getI赋值给了全局变量GI,getI又依赖于foo,所以GI存在时foo就不会
被回收
总结
- 闭包可看作保存状态的函数,而该状态对外部是不可见的
function foo(){
var i=1;
return function(a){
i+=a;
return i;
}
}
var add=foo();
console.log(add(0));//1
console.log(add(5));//6
- 巧用that指向外部变量
var foo={
i:1,
add:function(a){
that=this;
return (function(){
return that.i+a;
})()
},
getI:function(){
return (function(){
return this.i;
)()
}
}
var f=foo;
console.log(f.add(0));
console.log(f.getI());
console.log(f.add(5));
- 用闭包解决异步执行带来的问题
//一道经典的面试题
for(var i=0;i<3;i++){
setTimeout(function(){
alert(i)
},2000)
}
//实际弹出的是3 3 3,而非0 1 2
//因为setTimeout()中执行的函数会放置到另一个队列里面执行
//此时i早已变为3,当alert再执行时,会往上一个作用域中找i
//此时弹出的就是3 3 3
//解决办法如下
for(var i=0;i<3;i++){
(function(e){
/*** 该作用域的e依赖外层作用域的i ***/
setTimeout(function(){
alert(e)
},2000)
/*** 作用域结束 ***/
})(i);
}
//构造闭包,使循环赋值给e(即i的引用)