十三.闭包
闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。直观的说就是形成一个不销毁的栈环境。
先考虑一个问题
function foo(){
var a = "我是foo里面的a";
}
foo();//这段代码执行之后,foo里面的a还存在嘛?
结果显而易见,a已经不存在了。因为foo执行完了之后foo的作用域消失了,所以作用域里面的变量不见了,被销毁了。
咱们需要用某种方法来获得foo里面的a,怎么办呢?简单
function foo(){
var a = "我是foo里面的a";
return a;//将变量a给return出来
}
let b = foo();//此时b就获得foo里面的a了。
这里有一个概念需要大家理解:非对象数据类型都是非引用类型,那么b和a是什么关系。a是原始的值,b是a执行foo代码瞬间的值的拓印(副本)。也就是说如果我以某种方式修改了a的值,那么b的值没有任何改变。也谈不上使用foo的内部值了。其实此时foo内部的变量也被销毁了。
既然非对象不行,那么对象呢?
function foo(){
var o = {
"name":"GinTama"
}
setTimeout(function(){
o.name = "我被改变了";
},3000)
return o;
}
var b = foo();//此时我们foo内部的对象o已经被外部引用了,修改o的值
//并且b.name会被改变
发现了没?foo作用域里面的变量o被外部引用了。但是作用域还是消失了,只有o被保留了下来。如何保留下来foo的作用域呢?内部函数能访问外部函数的作用域,于是
function foo(c){
var num = c;
return function A(){
num++;
return num;
}
}
var b = foo(5);//b是什么?他保留了什么?
b();//6
b();//7
大家发现了没?保留下来了一个函数A,这个函数A可以访问foo的作用域里面的num并对他进行改变。这意味着num的作用域在foo执行完成之后保留下来了,保留在了函数A中。
上面就是一个简单的累加器
闭包:函数可以保留自己的作用域并可以访问它的作用域就产生了闭包。
闭包的影响: 会使得原有的作用域不消失,导致内存泄漏(可分配的内存的资源减少)。
闭包的作用
- 封装,私有化属性
function create(){
var pika = {
"money": 100
}
console.log("你的钱是:"+pika.money)
return {
"add":function(){
pika.money+=10;
console.log("你的钱是:"+pika.money);
},
"lost":function(){
Gin.money-=5;
console.log("你的钱是:"+pika.money);
},
"get":function(){
return pika.money;
}
}
}
var mint = create();//"你的钱是:100"
mint.add();//"你的钱是:110"
mint.lost();//"你的钱是:105"
var minter = create();
minter.get();//100
在这里pika这个对象完全变成了一个私有对象,里面的值已经无法直接获取,可以通过已经定义好的自定义的方法来访问它。
还有很多
比如:
function foo(){
var ss = 123
function A(){
console.log(sss)
}
window.$ = A;//将foo作用域里面的A存储到全局window下的$中也是形成闭包。
}
foo();
直接绑定到全局中
还有最常见的循环绑定的问题:
function foo(){
var arr = [];
for(var i = 0;i<10;i++){
arr[i]=function(){
console.log(i)
}
}
return arr
}
var mylist = foo()//mylist是一个存了10个函数的数组
//对数组每一个值执行的过程中就会出现意外情况,也可以用闭包来解决
function foo(){
var arr = [];
for(var i = 0;i < 10;i++){
arr[i]=(function(j){
return function(){
console.log(j)
}
})(i)
}
return arr
}
var mylist = foo();//此时梳理出来mylist是一个数组,每个打印出来就是对应的i的值
function foo(){
var arr = [1, 2, 3];
for(var i = 0;i<10;i++){
(function(j){arr[j]=function(){
console.log(j)
}})(i)
}
return arr
}
var mylist = foo()//mylist是一个存了10个函数的数组
//对数组每一个值执行的过程中就会出现意外情况,也可以用闭包来解决