JavaScript闭包,有女朋友的进来

什么是闭包

1.必须有函数嵌套函数;
2.内部函数必须使用到了外部函数的变量。
3.必须返回使用了外部变量的内部嵌套函数


怎么理解闭包

通(hu)俗(bian)来(luan)讲(zao),为了便于理解,接下来我们做个代入。

  • 你 = 外层函数myself
  • 女朋友 = 内层函数girlFriends
  • 钱 = 外层变量money
  • 老板 = 内存

下面这个人就是你,你有一个女朋友(任何你喜欢的女人都可以),你努力工作赚钱,然后你的女朋友花你的钱,女人花男人钱,这个就是“闭包”。
在这里插入图片描述

function myself() {
    var money = 100;
    function girlFriends() {           //不要在意后面的“s”
        return console.log('花钱', money);
    }
    return girlFriends();
}
myself();//花钱 100

上面的myself函数执行的时候,girlFriends(女朋友)可以随便使用money,虽然心疼,但是也还算合理对吧,用就用了。

可惜天不随人愿,函数的生命都是很短暂地,函数调用完成之后就没有了,内部的money也会释放掉,人死了就什么都没有了,但是有女朋友的人会有一点微妙变化。

function myself() {
    var money = 100;
    function girlFriends() {           
        return console.log('花钱', money);
    }
    return girlFriends;   //返回函数,而不是返回函数调用结果
}
myself()();              //增加一个(),保证返回的函数可以执行调用

//花钱 100

看看上面的代码,明明myself已经执行结束了,返回了一个函数,调用这个函数,居然还能访问到money,说明你死了,但是你的女朋友还是能花你的钱o(╥﹏╥)o

为什么函数执行完毕后,嵌套的函数还能访问到外层函数的变量

翻译一下上面的话,为什么你死了,你的女朋友还是能花你的钱。
这需要先讲讲钱是怎么挣的,你拼命工作,好不容易从老板(内存)那里挣了点儿钱。
在这里插入图片描述
但是这个老板很鸡贼,他给你钱后你必须时时刻刻盯着,如果没有人盯着这个钱,老板就会把钱拿走(垃圾回收)。
在这里插入图片描述
如果这个时候你有了女朋友(内部函数),并且返回了女朋友(内部函数),女朋友就可以帮你盯着钱,那么即便你死了,还是有人盯着钱,老板不能收走。所以只要有人在盯着这个钱,老板就不能收走。

接下来我们改造一下自己

function myself() {
    var money = 100;
    return function () {return money++;}; //这里省略了一下girlFriend的名称,直接返回一个匿名函数
}
var earnMoney = myself();
earnMoney();
earnMoney();
earnMoney();
console.log('earnMoney', earnMoney()); 
//earnMoney 103

定义一个变量earnMoney,把返回值赋值给这个变量,然后执行三次调用,结果输出了103。

  • 这里为什么会累加我们之前的数据?

因为我们的myself函数只执行了一次,那么money只初始化了一次,而且一直有函数在盯着存放money的内存,所以没有被回收,然后里面内嵌的函数执行了三次,那么money++运行了三次,所以返回103。也就是说现在我们已经从内存当中申请了一块区域用来存放“103”了,这块区域会一直存在,如何才能释放这块区域,只要让

earnMoney = null

就可以了。

上面这段话翻译一下,找一个“房子”,用来存放我们返回的“女朋友”,然后呢女朋友可以帮我们盯着钱,这时候钱还是100,这个女朋友很会理财,每执行一次,她就会让我们的钱增加1块,执行一次就增加一块,虽然“我们自己”已经挂了,但是女朋友还在,她执行了三次,我们的钱增加了3块。而且存钱的这个地方,别人访问不到,只有女朋友能访问。

现在老板(内存)必须要把钱收回来了,那只能销毁“房子”来销毁女朋友,进而没有人盯着钱了,那么好不容易挣的钱就被收走了。

闭包有什么好处?

function myself() {
    var money = 100;
    return function () {return money++;};
}
var earnMoney = myself();
var earnMoneyDouble = myself();
earnMoney();
earnMoney();
earnMoney();
earnMoneyDouble();
earnMoneyDouble();
earnMoneyDouble();
console.log('earnMoney', earnMoney());             //earnMoney 103
console.log('earnMoneyDouble', earnMoneyDouble()); //earnMoneyDouble 103

上面我们把返回函数赋值给了两个变量,分别执行两个变量,他们的计算互不影响,可以独立运行。这是因为计算的时候是在两块独立的内存上进行的。

接下来转换成我们熟悉的语言,现在找了两个房子,每一个房子都是调用myself(我们自己)之后得来的,说明我们很努力,挣了两份钱,分别放到两套房子里,这两份钱都让女朋友帮忙盯着,当女朋友去到第一个房子里执行理财的时候,第一个房子里面的钱就增加1块,这时第二套房子里的钱跟第一套。

所以“女人花男人的钱(闭包)“的好处就是,永远有钱花,而且钱只属于自己,不会被拿走,除非“房子”被铲掉。

接下来,该说一点男人们梦寐以求的事情了

  • 如果有好几个女朋友,那么该怎样对待她们呢?

答案就是,一碗水端平,每个都要疼,都得给钱花(为了让你们听懂,我才这样说的)

回到正题,请看代码

function myself() {
	var manyGirlFriends = [];
	for (var i = 0; i < 10; i++) {
		manyGirlFriends[i] = function () {
			return i;
		};
	}
	return manyGirlFriends;
}
var girlsHouse = myself();
girlsHouse[5]();
console.log('girlsHouse[1]()', girlsHouse[1]()); // girlsHouse[1]() 10
console.log('girlsHouse[2]()', girlsHouse[2]()); // girlsHouse[2]() 10
console.log('girlsHouse[3]()', girlsHouse[3]()); // girlsHouse[3]() 10
console.log('girlsHouse[4]()', girlsHouse[4]()); // girlsHouse[4]() 10
console.log('girlsHouse[5]()', girlsHouse[5]()); // girlsHouse[5]() 10

上面代码里面,我们循环创建10个闭包,然后想让每个闭包返回当前的i,但是当myself返回的时候,for循环已经结束,所有闭包都会共享一个i,那么结果就是全都会返回10。

接下来是大家期待的翻译时间

你有10个女朋友,你希望第一个女朋友分一块钱,第二个分两块钱,依次类推,但是这些女朋友不会听你的,她们是好姐妹,有钱一起花,每个人都能支配你赚来的钱。

  • 那么有没有什么方法能达到那种互不影响的效果呢?

还真有!立即执行函数

function myself() {
	var manyGirlFriends = [];
	for (var i = 0; i < 10; i++) {
		(function (i) {
			manyGirlFriends[i] = function () {
				return i;
			}
		})(i);
	}
	return manyGirlFriends;
}
var girlsHouse = myself();
girlsHouse[5]();
console.log('girlsHouse[1]()', girlsHouse[1]()); //girlsHouse[1]() 1
console.log('girlsHouse[2]()', girlsHouse[2]()); //girlsHouse[2]() 2
console.log('girlsHouse[3]()', girlsHouse[3]()); //girlsHouse[3]() 3
console.log('girlsHouse[4]()', girlsHouse[4]()); //girlsHouse[4]() 4

或者还可以使用ES6的 let,把for循环当中var i = 0替换为 let i = 0就可以了。

关于立即执行函数和let作用域问题,我们可以单独抽出来讨论一下,请关注我之后的博客

本片文章借鉴了《JavaScript权威指南》一书,还有很多技术界的前辈们,如果涉及侵权的地方,请联系我删除,另外画画和举例子是为了有直观的感受,并无恶意,请各位不要对号入座。还有本文是自己对于闭包和JS垃圾回收的一点浅显理解,有不准确的地方,请大佬多多指点,小弟拜上。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值