闭包是什么
闭包是一个函数(一个作用域可以访问另一个作用域的局部变量)
闭包的产生
但凡是内部的函数 被保存到了外部 就一定产生了闭包
多个函数嵌套 把里面的函数保存到了外部
闭包的缺点
闭包会导致原有作用域链不释放,造成内存泄漏(占用内存)
闭包的作用
延申了变量的作用范围
实现公有变量 :累加器
可以做缓存(存储结构)
可以实现封装,属性私有化
模块化开发,防止污染全局变量 案例
累加器(不依赖外部变量)
function add(){
var count = 0;
function demo(){
count++;
console.log(count)
}
return demo;
}
var counter = add();
counter(); //1
counter(); //2
counter(); //3
counter(); //4
存储结构
function test (){
var num =100
function a(){
num++
}
function b(){
num--
}
return [a,b]
}
var myArr = test();
myArr[0](); //101
myArr[1](); //100
产生问题
function test(){
var arr = [];
for(var i=0;i<10;i++){
arr[i] = function(){
console.log(i)
}
}
return arr
}
var myarr = test()
for(var i=0;i<myarr.length;i++){
myarr[i]()
}
//结果输出
//10 10 10 10 10 10 10 10 10 10
//分析
test 定义(defined) test.[[scope]] ==> 0:GO
test 执行(doing) test.[[scope]] ==> 0:testAO
1:GO
test 执行(doing) 预编译
1,创建AO对象
2,把函数内的变量行程挂载到AO对象 赋值undefined
testAO{
arr:undefined,
i:undefined
}
3,形参实参统一
4,找到函数声明,并赋值函数体
for循环
i:0
testAO{
arr:[0:function(){...},....]
i:0
}
.....
i=9
testAO{
arr:[0:function(){...},....]
i:9
}
i=10
循环终止
testAO{
arr:[0:function(){...},....]
i:10
}
myarr[i]()调用
console.log(i);//10
arr[i] 与 函数表达式的 i
arr[i] 是变量 立即执行 获取执行时的i
函数表达式的 i 函数没有执行的时候 是引用值 i值不确定
执行时 获取函数表达式执行时的i
解决问题 就想输出 0~9
// 立即执行函数
function test(){
var arr = [];
for(var i=0;i<10;i++){
(function(j){
arr[j] = function(){
console.log(j)
}
})(i)
//
}
return arr
}
var myarr = test()
for(var i=0;i<myarr.length;i++){
myarr[i]()
}
// 0 ~ 9
// 执行过程分析
test 定义(defined) test.[[scope]] ==> 0:GO
test 执行(doing) test.[[scope]] ==> 0:testAO
1:GO
test 执行(doing) 预编译
1,创建AO对象
2,把函数内的变量行程挂载到AO对象 赋值undefined
testAO{
arr:undefined,
i:undefined
}
3,形参实参统一
4,找到函数声明,并赋值函数体
for循环
i=0
立即执行函数
立即执行函数 定义(defined)
创建AO对象 01AO
把函数内的变量行程挂载到AO对象 赋值undefined
o1AO{
j:undfined
}
形参实参统一
o1AO{
j:0
}
立即执行函数 执行(doing) 01.[[scope]] ==> 0:01AO{j:0}
1:testAO{arr:[0:function(){}]}
2:GO
立即执行函数 执行完 销毁执行期上下文 (产生闭包 arr[0]继承了立即执行函数的作用域链 销毁不掉) 销毁立即执行函数
i=1
立即执行函数
立即执行函数 定义(defined)
创建一个新的AO对象 o2AO
把函数内的变量行程挂载到AO对象 赋值undefined
o1AO{
j:undfined
}
形参实参统一
o1AO{
j:1
}
立即执行函数 执行(doing) 02.[[scope]] ==> 0:02AO{j:1}
1:testAO{arr:[0:function(){}]}
2:GO
立即执行函数 执行完 销毁执行期上下文 (产生闭包 arr[1]继承了立即执行函数的作用域链 销毁不掉) 销毁立即执行函数
。。。。
i=10
循环终止
调用
for(var i=0;i<myarr.length;i++){
myarr[i]();
//function(){
// console.log(j)
//}
}
marr[0]();
marr[0].[[scope]] ==> 0:marr[0]AO
1:01AO{j:0}
查找变量 j (从作用域链顶端依次向下查找 [[scope]] 0->n)
0:marr[0]AO 没有j 找下一级 1:01AO
1:01AO{j:0} 即j=0
marr[1]();
marr[1].[[scope]] ==> 0:marr[2]AO
1:02AO{j:1}
0:marr[1]AO 没有j 找下一级 1:02AO
1:02AO{j:1} 即j=1
....
结果 0~9
属性私有化
function Per(name,age){
var page = 0;
this.name = name;
this.age = age;
this.getPage = function(){
consle.log('page',page);
}
this.add = function (){
page ++
}
}
var per = new Per('per',18)
//page 就是per对象的私有化属性
console.log(per.page);//undfined 访问不到
per.getPage();// 0 只有它自己的方法才能访问
//是因为产生了闭包 函数作用域被保存到了外面