历时一个月,我终于搞懂了闭包

lxf2023-03-17 07:40:01

我终于搞懂了js里面的闭包

一提到闭包,大家就会想起JavaScript中的闭包,没错,闭包是JavaScript的一大特色,这是因为有了闭包,让JavaScript可以做一些特别的工作。

但是闭包对于很多人来说很亲切却又很陌生。为什么呢?
因为闭包在JavaScript中非常常见,但是呢闭包又是JavaScript中的一大难点,被称作JavaScript里面的三座大山。

今天我给大家带来我对闭包的理解:

1.准备工作

在了解闭包之前,我们需要知道两个东西:

  • 作用域
  • 函数在定义时的一些小知识

1.1作用域

在JavaScript中,定义变量时所在的作用域,决定了这个变量的可见性。

JavaScript中有两种作用域:全局作用域与局部作用域。

  • 全局作用域:在这里定义的变量,整个代码都可以访问到这变量。
  • 局部作用域:在这里定义的变量,在该局部作用域和上级作用域可以访问到

也就是说,全局作用域下可以有多个局部作用域,在某个局部作用域里面也可以存在多个(子)局部作用域。

我们可以这样理解,全局作用域是祖先作用域,剩下的作用域可以被分为子局部作用域、孙局部作用域、、、、、、

就像这样:

历时一个月,我终于搞懂了闭包

当我们需要查找一个变量的值的时候,我们JavaScript的引擎就会这样去寻找:

如果是在局部作用域查找该变量的值,JavaScript首先会在本局部作用域查找这个变量,如果查找到,就使用该变量;如果没有找到,就会往上一级作用域查找,依次类推。这就是我们所说的就近原则。

我么可以发现:查找变量都是向本作用域或者上级作用域查找。而不会向下级作用域查找,这是因为我们不能访问下级作用域的变量。但是闭包的出现,就能解决这个问题。

不着急,我们慢慢往下看。

1.2函数定义时的一些小知识

我这里只讲述函数定义时作用域的知识:

函数在定义的时候就会与定义时所在的变量作用域绑定,就比如函数在全局作用域下定义,那么这个函数就一直处在全局作用域;如果函数在某一个局部作用域下定义,那么该函数就与这个局部作用域绑定。

并且在函数内部也会形成一个局部作用域,这里面定义的变量只能在函数内部使用。

2.上正菜:闭包

在了解了前面的知识之后,我们就可以开始我们今天的正菜了:闭包。

前面我们知道函数内部是一个局部作用域,并且在函数外部是不能访问到函数内部的变量的。

function f(){
	let a = 2;
	console.log(a);
}

f();// 2
console.log(a);// 报错 变量a没有定义

有了闭包之后,这一切都不一样了。闭包:就是能够读取其他函数内部变量的函数。是的,你没有看错,闭包其实是一个函数。

我们先弄一个闭包出来,然后我们再来讲讲闭包是怎么实现的。

function f1(){
	let a = 10;
	let b = 20;
	function f2(){
		return a;
	}
	return f2();
}
let c = f1();
console.log(c);// 10

很神奇吧,在函数外部,我们居然读取到了函数内部变量的值。

这是因为,f1函数内部定义了一个f2函数,因为f2函数是在f1内部定义的,多以f2的作用域就为f1局部作用域里面的又一个子局部作用域。

根据前面我们的铺垫可知:

  • f2函数作用域内可以访问到f1的变量。

所以当f2作为f1的返回值的时候,就把f2能访问到的变量的值也返回回去了。这样就导致,外部调用f1函数的时候,返回一个f2函数,f2函数里面又可以访问到f1内部的变量。最终f1函数外部也能访问f1内部的变量了。

有点绕,但是闭包就是这样一个原理

2.1闭包作用

  1. 闭包可以读取函数内部的变量
  2. 闭包可以使得变量的值始终保存在内存

针对第一点,闭包可以实现对象的某些私有方法
第二点,这提醒我们要慎用闭包,虽然它很灵活,但是不小心开发者就会写一个闭包出来,有可能会造成内存泄露。

总结

一直在路上,2023新的一年,新的开始。坚持不懈的学习,终会有成功的那一天。