JavaScript 闭包篇

1:闭包

(1)先来看个例子 :

function a(){
	function b(){
		var bbb = 234;
		console.log(aaa);
	}
	var aaa = 123;
	return b;
}
var glob = 100;
var demo = a();
demo();

解析:我们来看这个例子,简便的分析一下,在全局有一个函数 a,变量 glob、demo, 然后 a 执行,执行前 a 的作用域链里放的是 a 的 AO 和 GO,然后在 a 函数里有一个函数 b 和变量 aaa,b 函数最开始拿的是 a 的劳动成果(a 的 AO 和 GO),但是最重要的是,b 函数没有被执行,在 a 函数结束的时候把 b 函数返回了出去,在全局 var 一个 demo 等 于 a 执行,就是说现在把 a 函数的返回值赋给了 demo,也就是说 demo 里边现在装的是 b 函数。好,a 函数现在执行完了,他要销毁自己的 AO,我们看着好像就连同 b 函数一块儿被销毁了,然而并没有,全局的 demo 现在就是里边的函数 b,而且手里还攥着 a 的劳动成果,就是说虽然 a 把自己的 AO 销毁了,然而 b 手里还有 a 的 AO 和 GO 呢,而 且还被保存到了外部的 demo 里,所以你在外边执行 demo,就等于执行函数 b,执行时要访问 aaa,先创建自己的 AO 放到作用域链最顶端,然后发现自己的 AO 里没有 aaa, 然后往下找,找到 a 的 AO 有变量 aaa,然后输出得 123,我们视觉上看着好像 b 函数被保存到了外部,再去访问函数里的 aaa 好像是不行的,然而事实上是可以的,这个过程就叫做闭包。

注意:这里把 b 扔给 demo 扔的是引用值,就等于把 b 的地址扔给 demo 了。demo 和 b 就相当于同一个人的不同名字,所以 demo 执行就等于 b 执行。

闭包的产生:但凡内部函数被保存到了外部,它一定生成闭包。例如上边的,内部函数会保存外部函数的劳动成果,然后还没执行呢,就通过 return 的方式被保存到了外部,一保存到外部,那么 a 函数想删除自己的 AO 都删除不了了,因为 b 始终攥着呢。

(2)闭包的应用 :

这里为了方便理解我们再来看一个例子:

function a(){
	var num = 100;
	function b(){
		num ++;
		console.log(num);
	}
	return b;
}
var demo = a();
demo();
demo();

解析:a 执行时产生了自己的 AOGO,然后 b 在定义的时候拿到 a的劳动成
果,a 函数最后把 b 返回给了 demo,然后 a 销毁自己的 AO,然而 demo现在
就是 b 函数,他还保存着 a 的 AOGO,所以 demo第一次执行的时候 b 先
创建自己的AO,然后自己的 AO 里边没有num,就去 a 的 AO 里拿,然后++,输
出得 101,销毁自己的 AO,然后第二次 执行时在创建自己的 AO,没有num,然
后去 a 的 AO 里拿,此时 num是 101,再++,输出得 102,这里每次执行创建
和销毁的是 b 的 AO,然而里边并没有东西,他始终拿的是 a 的 AO 里的num,
a 的 AO 一直存在着。

(3)闭包的现象 :

当内部函数被保存到外部时,就会生成闭包,闭包会导致原有作用域链不释放,造成内存泄露。

解释:例如上边的例 1,本来 a 执行完之后就会销毁自己的 AO,但是 b 被扔出来之后他说你销毁了也是白扯,我还拿着呢!所以他就会导致作用域链该释放的时候不释放,你有意做的闭包还好,假如闭包是无意做的,那就很占内存空间了。所以就会造成内存泄露,什么叫内存泄露?可以这么理解,你占得内存多了,剩余的内存就少了,我们关注剩余的内存,他是不是越来越少?就好像泄露了一样。所以这得反向的理解。

(4)闭包的作用 :

作用一:实现公有变量,比如函数累加器:
function(){
	var count = 0;
	function demo(){
		count ++;
		console.log(count);
	}
	return demo;
}
var counter = add();
counter();
counter();
counter();

解析:我们用闭包就可以做一个函数累加器,在 add 里边先定义一个变量 count,然后定义一个函数 demo,demo 里实现 count++,最后把 demo 扔给全局的 counter,自此之后 counter 就会把 count 无限用了,你每调用一次 counter 他就会在原有的基础上加 一次,这样做就更加模块化,你每执行一次方法他就会累加一次,结构化更好。

作用二:可以做缓存(存储结构)
function test(){
	var num = 100;
	function a(){
		num ++;
		console,log(num);
	};
	function b(){
		num --;
		console.log(num);
	};
	return [a,b];
}

var myArr = test();
myArr[0]();
myArr[1]();

解析:首先定义一个 test 函数,test 里边 var 一个 num 等于 100,还放着两个函数 a 和 b,a 函数里边让 num++,b 函数里边让 num- -,然后在 test 最后通过数组的方式把 a 和 b 都扔给外部的 myArr,这也可以形成闭包,你在下边执行 myArr 的第 0 位就等于 a 函数执行,执行 myArr 的第 1 位就等于执行 b 函数,先执行 a 函数,a 拿的是 test 的 AO,num++后输出得 101,再执行 b 函数,b 和 a 同级,拿的也是 test 的 AO,由于刚才 num 被 a++后得 101,所以再 - - 输出得 100.

示例:

function eater(){
	var food = '';  //food 初始化
	var obj = {
		eat : function(){
			console.log("im eating" + food) 
			food = '';  //food 清空
		}
		push : function(myFood){
			food = myFood;  //给 food 赋值
		}
	}
	return obj;
}
var eater1 = eater();
eater1.push("banana");
eater.eat();
作用三:可以实现封装,属性私有化(高级应用,后边讲)
作用四:模块化开发,防止污染全局变量(高级应用,后边讲)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山大王杨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值