JS学习笔记(十一)什么是闭包?闭包和匿名函数的区别

JS学习笔记(十一)

本系列更多文章,可以查看专栏 JS学习笔记



一、作用域链的创建和使用

每个JavaScript函数都是一个对象,对象中有部分属性仅供javascript引擎存取。[[scope]]属性只能被JS引擎存取。

函数执行时,每个执行上下文中都会有一个包含其中变量的对象

-(1)全局上下文中的叫变量对象,它会在代码执行期间始终存在
-(2)函数局部上下文中的叫活动对象,它只在函数执行期间存在

1. 作用域链的创建

在这里插入图片描述

  • (1)定义sum()函数时: 创建函数的作用域链,预装载全局变量对象,并将其保存在内部属性[[scope]]中
  • (2)调用sum()函数时:
    • 创建相应的执行上下文,复制函数的[[scope]]属性,来创建其作用域链
    • 创建函数的活动对象,并将其推入作用域链的前端【0位置是前端,最后一个永远是全局上下文的变量对象】
  • (3)sum()函数执行完毕后: 局部活动对象会销毁,内存中仅剩全局作用域。

2. 作用域链的使用

因此函数内部的代码访问变量时,会沿着作用域链从前端(0)位置向后,从作用域中根据给定的名称查找变量。


二、匿名函数和闭包

1. 匿名函数

匿名函数是指 没有实际名称的函数

// 匿名函数 -1 :函数表达式
let f1 = function () {};
// 匿名函数 -2 :立即执行函数
(function (){})();

注:匿名函数不是闭包!!! 但是闭包和匿名函数有关

2. 闭包

闭包指的是,那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的。

  • (1)在函数A中,定义一个内部匿名函数B作为函数A返回值,并在内部函数B中使用其他函数作用域(A)的变量(形成闭包)
  • (2)在调用函数A时,定义一个新变量C接收函数A的返回值,得到一个新的函数C
  • (3)函数A执行完毕后,相应的作用域链会销毁,但是函数A的活动对象仍在内存中,因为其内部属性被使用中
  • (4)调用新得到的函数C,即可实现对函数A内部属性的私有化访问
  • (5)若需销毁函数A的活动对象,只需将C赋值为null即可
function wrapper() {
	let count = 0;
	// 此内部函数是匿名函数,因为使用其他函数作用域的变量,故形成了闭包
	return function () {
		// 实现了对其它函数作用域变量的访问
		console.log(++count);
	};
}

// wrapper()函数执行完毕,其执行上下文作用域链会被销毁
// 但它的活动对象仍然在内存中(因为匿名函数需要使用此变量)
let result = wrapper();
// 此时调用匿名函数,访问同一个wrapper()的活动对象
result(); // 1
result(); // 2
result(); // 3

// 销毁匿名函数后,wrapper()的活动对象才被销毁
result = null;

在这里插入图片描述
当函数wrapper()执行完毕以后,其作用域链被销毁,但仍会保留wrapper()函数的活动对象,其中含有变量count。
此时闭包活动对象中的count值,是wrapper()函数活动对象的值,在反复执行result()时,实际操作的是wrapper()函数活动对象的值,故输出为1 2 3,而不是1 1 1;


结尾

部分内容参考《ECMAScript 6 入门》《JavaScript权威指南》《JavaScript高级程序设计》,如有错误,欢迎评论区指正

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

想要大口炫榴莲

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

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

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

打赏作者

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

抵扣说明:

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

余额充值