04-闭包

闭包:函数嵌套函数,内部函数就是闭包,只有函数内部的子函数才能读取内部变量。

先上一个经典的闭包:

function outerFun () {
	let a = 10;
	function innerFun () {
		console.log(a);
	}
	return innerFun;
}
let fun = outerFun();
fun(); //10

将内部函数作为外部函数的返回值;

特性:

内部函数没有执行完成,外部函数变量不会销毁。

形成一个不销毁的私有作用域,除了保护私有变量不受干扰以外,还可以存储一些内容。

作用域链:

我们⼀般将作⽤域分成:

  • 全局作用域
  • 局部作用域,就是函数作用域,只能在函数内部访问,不能在函数以外去访问
  • 块级作用域,⼤括号中使⽤ let 和 const 声明的变量存 在于块级作⽤域中。在⼤括号之外不能访问这些变量

例1:

let a = 10;
let b = 20;
function fun() {
	let a = 30;
	let c = 40;
	function fn() {
		let a = 50;
		let d = 60;
		function f() {
			console.log(b);
		}
	}
}

 

 正常情况下,函数执行完成,内部变量会自动销毁(释放内存空间)

在函数内部可以访问内部定义的变量

function fun() {
	let a = 10;
	console.log(a); //10
}
fun(); 

在函数外部不能访问到函数里面定义的变量,因为函数执行完成,变量就销毁了

function fun() {
	let a = 10;
}
fun(); 
console.log(a); //a is not defined

闭包的作用:

保存,保存外部函数和私有变量

保护,内部变量私有化,不会像全局变量受污染

模块化,团队协作开发时,使用闭包可以让各自的代码存储在私人范围内,避免变量冲突

闭包有两大作用:保存和保护

1) 保存:

函数执行形成一个私有作用域,函数执行完成,当前私有作用域(栈内存)中的某一部分内容被栈内存以外的其他东西(变量/元素的事件)占用了,当前栈内存不能被释放掉,也就形成了不销毁的私有作用域(里面的私有变量也不会被销毁)

函数执行返回了一个引用数据类型堆内存地址(并且堆内存隶属于这个作用域),在外面有一个变量接收了这个返回值,此时当前作用域就不能被销毁(想要销毁,只需要放外面的变量赋值为null,也就是不占用当前作用域中的内容了)

2) 保护:

形成私有作用域,保护里面的私有变量不受外界干扰
例如:团队协作开发,每个开发者把自己代码存放在一个私有作用域当中,防止相互之间的冲突;把需要共别人使用的方法,通过return或者window.XXX暴露在全局下即可(比如jQuery源码种也是利用保护机制实现的)

真实项目中,我们利用这种保护机制,实现团队协作开发(避免多人用同一个命名,导致代码冲突的问题)

闭包使用场景

1、setTimeout()

原生的setTimeout传递的第一个函数不能带参数,通过闭包可以实现传参效果。

function f1(a) {
	function f2() {
		console.log(a);
	}
	return f2;
}
let fun1 = f1(1);
setTimeout(fun1, 1000); // 1秒后打印1

2、回调

定义行为,然后把它关联到某个用户事件上。代码通常会作为一个回调(事件触发时调用的函数)绑定到事件。

例:点击字体改变大小

<body>
	<a href="#" id="size-12">12</a>
	<a href="#" id="size-20">20</a>
	<a href="#" id="size-30">30</a>
</body>
<script>
	function changeSize(size) {
		return function() {
			document.body.style.fontSize = size + 'px'
		}
	}
	let size12 = changeSize(12);
	let size20 = changeSize(20);
	let size30 = changeSize(30);
	document.getElementById('size-12').onclick = size12;
	document.getElementById('size-20').onclick = size20;
	document.getElementById('size-30').onclick = size30;
</script>

3、函数防抖

  • 如果timer为true,说明正在计时且触发了相同事件,所以要取消当前的计时,重新计时
  • 否则就表示没有在计时,就开启一个计时
function debounce(fn, delay) {
	let timer = null;
	return function() {
		if (timer) {
			clearTimeout(timer)
			timer = setTimeout(fn, delay);
		} else {
			timer = setTimeout(fn, delay);
		}
	}
}

4、封装私有变量

function add() {
	let num = 0;
	let obj = {
		inc: function() {
			num ++;
			return num;
		}
	}
	return obj;
}
let reault = add();
console.log(reault.inc()); //1
console.log(reault.inc()); //2
console.log(reault.inc()); //3

闭包有什么作用?

猜你喜欢

转载自blog.csdn.net/iaz999/article/details/131243943
今日推荐