闭包
在内部函数使用外部函数的变量,就会形成闭包。闭包保留了外部环境的引用
如果内部函数被返回到了外部函数的外面,在外部函数指向完成后,依然可以使用闭包里的值
闭包的形成
在内部函数使用外部函数的变量,就会形成闭包
例子1:
function a{
var aa = 100
function b{
//在内部b函数里使用外部a函数的变量aa,此时就**形成了闭包**,aa:100
//但是因为没有return回去所以**没有保持闭包**
console.log(aa)
}
b()
}
a()
闭包的值存储在closure中,但因为没有return所以不会保持,b函数执行完,这里的闭包便会消失(有很多js书籍也没有很权威直接的说明这里是否形成闭包,只不过在浏览器debug运行时确实有闭包)
例子2:
function a{
var aa = 100
function b{
//形成了闭包 {b:fun}
console.log(b)
}
b()
}
a()
代码执行顺序:由上往下执行,先检查函数a,在再下面调用函数a。
1.产生a的AO对象
aAO:{aa: undefined;b:function}
2.调用函数a
3.a的AO对象变成:
aAO:{aa: 100;b:function}
4.产生b的AO对象
bAO:{}
[[scopes]] - 0:bAO ;1:aAO; 2:GO
2.闭包的保持
如果希望在调用函数后,闭包依旧保持,就需要将内部函数返回到外部函数的外部
例子1:
function a(){
var num = 0
function b(){
console.log(num++)
}
return b
}
var demo = a()
demo()
demo()
执行过程:
预编译:GO:{a:function;demo:undefined}
1.var demo = a()这里执行a()
产生aAO{num:0;b:function}
GO变成{a:function;demo:b(){console.log(num++)}}
2.第一个demo()
等于执行b(),产生bAO{} [[scopes]] - 0:bAO;1:aAO;2:GO
num++,num在外部a()函数,所以这里形成了闭包。
因为num++是先打印原来的值再++;所以这里打印的值是0,num的值是1
3.第二个demo()
等于执行b(),产生新的bAO{} [[scopes]] - 0:bAO;1:aAO;2:GO
num++,num在aAO作用域里num = 1,打印原来的值1;num的值是2
这就是闭包的保持
闭包的条件
1.闭包要形成:在内部函数使用外部函数的变量
2.闭包要保持:内部函数返回到外部函数的外面
闭包的应用
1.一般情况下,函数外部是访问不到函数内部的变量的,所以需要通过闭包来操作函数里的变量
2.实现封装
3.防止全局变量的污染
例子:
function a(){
var name
function Setname(name) {
this.name = name
}
function Getname() {
return this.name
}
return {
Setname:Setname,
Getname:Getname
}
}
var b = a()
console.log(b);
b.Setname('xiaoe');
console.log(b.Getname());
运行结果: