javascript 简简单单的闭包

正常情况下外部变量无法访问函数内部的变量

如:

// 上级(外部)作用域的变量是无法访问下级(内部)作用域的变量
// 外部无法访问内部,内部无法访问外部==>这是JavaScript的作用域链
function fun(){
let num=10 // num是函数私有的
}
let test=num // test 拿不到函数内部的数据,除非函数主动提供

什么是闭包

闭包就是外部(全局)变量依赖于内函数,内函数又依赖于外函数,由于存在这种依赖关系,导致GC无法回收该外部函数,该外部函数就是一个闭包函数。
判断是否是闭包的核心要点,是判断这个外部变量或者内部函数能否脱离依赖单独存在
你看看下面哪个是闭包

function funA(){
	let num=10
	return num  没有中间商去传递依赖关系,没构成完整依赖链
}
let numA=funA()

function funB(){
	let num=10
	const obj={ 
		num,
		get() {  
			return num  没有脱离依赖,num是函数的
		}}
	return obj
}
let numB=funB()
...
numB=null // 手动回收funB

function funC(){
	let msg='不是闭包'
	return obj={msg}  脱离了依赖,msg是自己的
}
let numC=funC()

在判断是否是闭包之前,你需要知到哪些变量是引用类型,哪些变量是值类型funAfunB都返回了一条数据,然而numA存储的是funA返回的值,funA不是闭包,它执行完后就会被GC回收掉;numB存储的是funB返回的地址(引用),funB就是闭包,GC无法回收,需要手动回收numB=null,或者整个程序结束后,回收numB时一起回收。
顺便提一嘴:全局变量是在程序结束之后被销毁,局部变量在没有形成闭包的情况下,代码块结束后就被销毁;如果形成了闭包,那么局部变量的生命周期与引用它的外部变量保持一致。

用一张图表示闭包,要想形成闭包需要完整的依赖关系,并且这个依赖关系需要持续存在
在这里插入图片描述

闭包的特点

  1. 函数作用域的变量是私有的,不允许直接修改
  2. 允许对外提供公共接口去修改,获取私有变量
  3. 由于闭包不会被回收(不会创建新的),它的私有变量会被一直持有(缓存)
const Module = (function moduleFun() {
	let private_variable = 10  私有变量
	const module = {   对外的访问接口
		get() {    允许外部访问
			return private_variable 
		},
		set(val) {  允许外部修改
			private_variable = val
		},
		add(count) {  缓存计算结果
			private_variable += count
		}
	}
	return module
})()
Module.get() //10
Module.set(29)
Module.get() //29
Module.add(10)
Module.get() // 39
Module.add(10)
Module.get() //49

闭包的用处

  1. 可以用来模拟类
  2. 可以用来模拟命名空间,当作模块使用
  3. 可以用来缓存数据的计算结果

出一个题

判断下面函数是不是闭包,并写出输出结果
提示:思考obj内部的属性是自己的还是函数的

是闭包
function funA() {
	let num = 10
	const obj = {
		num, 只有一瞬间的依赖关系
		get() {
			return num 依赖于函数的num是闭包
		}
	}
	return obj
}
let numA = funA()
console.log(numA.num++) //10
console.log(numA.get()) //10


不是闭包
function funB() {
	let num = 10
	const obj = {
		num,  只有一瞬间的依赖关系
		get() {
			return this.num 用的是它自己的num,不是闭包
		}
	}
	return obj
}
let numB = funB()
console.log(numB.num++) //10
console.log(numB.get()) //11

不是闭包
function funOA() {
	const user = { name: "hod", age: 22 }
	const obj = {
		user,  只有一瞬间的依赖关系
		get() {
			return this.user  使用的是自己的user,不依赖于函数
		},
		1,修改的是自己的user不是闭包。
		2.由于函数和对象使用同一个user,这里被修改函数的user也会被修改
		set() {
			this.user.name = "lis" 
		}
	}
	return obj
}
let objA = funOA()
objA.set()
console.log(objA.get()) //{ name: 'lis', age: 22 }


是闭包
function funOB() {
	const user = { name: "hod", age: 22 }
	const obj = {
		user,
		get() {
			return user 依赖于函数的user形成闭包
		},
		set() {
			this.user.name = "lis" 
		}
	}
	return obj
}
let objB = funOB()
objB.set()
console.log(objB.get()) //{ name: 'lis', age: 22 }



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值