当前位置: 首页 > 科技观察

动画:什么是闭包?

时间:2023-03-19 18:49:56 科技观察

是初学者学习前端的小伙伴,感觉HTML和CSS太简单了,没有挑战性。那是你没学过JS。JS中有太多的概念,刚开始学的时候容易混淆,比如this,原型链,闭包等等,既重要又难。但是当你理解之后,你会发现它非常简单易懂。因为小鹿是暑假去面试的,每次面试基本上都要问问题,不仅要知道理论,还要问你在实际项目中的实践。很多人在实战中往往会忽略这部分内容。今天的内容是JS中的一个重点,也是面试的必考点。它经常用在项目中,那就是邀请我们神圣的“闭包”出现。你可能没有听说过这个词,也可能听说过但不理解,不知道怎么用,下面我们就用零和小鹿的动画来搞清楚“闭包”的概念.思维导图1.什么是闭包?学习一个陌生的概念,首先要了解它是什么?也就是说,什么是闭包?要完全掌握闭包,必须清楚函数作用域、内存回收机制、函数域继承。下面简单说说这些概念。1.函数作用域作用域的概念,如果形象地描述,可以认为是一个封闭空间,在这个封闭空间内只允许进行一些操作,这个封闭空间也称为私有作用域。在JS中,函数的执行会在内存中创建一个私有作用域——一个封闭的空间。例如,在函数中定义一个变量,只能在函数的私有作用域(即封闭空间)内使用。只要超出这个范围,变量就找不到了。而函数执行后,这个私有作用域(封闭空间)就会被销毁。有一种情况是不会被销毁的,那就是“关闭”,后面会提到。2、内存回收机制内存回收机制就是不再使用的内存,我们的系统会自动回收它,腾出空间供其他程序使用。回收规则是什么?内层函数引用外层函数的变量,即使外层函数执行完毕,外层函数的作用域也不会被破坏。从而形成一个不被破坏的私有作用域。某个变量或对象被引用了,所以在回收时不会释放,因为被引用就意味着被使用,回收器不会回收被引用的变量或对象。3.范围继承所谓范围继承,就好比儿子可以继承父亲的财产。比如小鹿有一个大盒子作为parentscope,然后在这个大盒子里面放了一个小盒子作为childscope。我们规定大盒子里的东西在小盒子里可以获取,小盒子里的东西大盒子不能获取,这叫作用域继承。在JS中,道理是一样的。我们在函数内声明另一个函数。内层函数可以访问外层函数作用域内的变量,但外层函数不能获取内层函数作用域内的变量。好了,理解了上面的概念之后,什么是闭包对你来说就不再是问题了。用大白话来说,什么是闭包就是在函数内部定义一个函数。这个内部函数始终保持对外部函数范围的访问(小盒子总是可以访问大盒子)。函数执行形成一个私有作用域,保护内部的私有变量不受外界干扰。除了保护私有变量外,它还可以存储一些内容。这种模式称为闭包。动画实现:2.闭包的作用是什么?想必你对闭包还是一知半解,没关系,我们继续深入了解吧。闭包的主要作用是什么?为什么要使用闭包?按照上面对闭包的解释,外部函数返回了内部函数,但是外部函数还是有访问范围的,因为外部一直保持着引用。这使我们发现可以在哪里使用它。不是有一个没有被破坏的块作用域吗?我们可以用它来保存一些内容,也可以用它来保护一些私有变量。我们得出结论,闭包有两个功能,保护和保存。3.闭包的应用场景既然我们知道了闭包的作用是保存和保护,那在实际项目中用在什么地方呢?1.保护团队开发时,每个开发人员都将自己的代码放在一个private范围内,防止彼此之间的变量命名冲突;通过return或者window.xxx将需要提供给他人的方法暴露给全局环境。jQuery的源代码中也使用了这种保护机制。2.保存作为制表符关闭的解决方案。我们经常在网页中使用tabs,但是它有一个问题,就是索引带来的问题其实和下面的经典面试题是一样的。4、经典的闭包面试题循环绑定事件导致索引有什么问题?如何解决这个问题呢?此时运行程序,得到的结果就是len的值。为什么会出现这种问题,如何解决呢?原因很简单。所有事件绑定都是异步的。当点击事件被触发,方法被执行时,循环就已经结束了。多说一点,什么是同步,什么是异步?同步:JS中当前任务没有完成,不会执行后面的任务。只有当当前任务完全完成后,才会执行后面的任务。异步:JS中当前任务还没有完成,需要等待一段时间才能完成。这时候我们可以继续执行下面的任务。解决方法:执行click事件时,会在privatescope中查找i的值。这时候privatescope里面没有i,再回到globalscope去查找。这时候全局范围内的i已经改变了。因此,创建一个私有范围的i。方法一,关闭的方式。闭包终于派上用场来存储私有变量。但是封闭方案既有优点也有缺点。优点是通过创建私有作用域(闭包)来解决。几次循环后,创建了几个私有范围(闭包)。然后,每个私有作用域都有一个私有变量i,存储的值就是循环值。缺点是会产生多个未销毁的私有作用域(堆内存),对性能有一定影响。第二种方法是使用自定义属性。我们给每个对象加一个index属性就OK了。最终的解决方法,这是ES6中的知识,因为之前JS中没有块级作用域的概念,ES6中是有的,Let声明的变量可以更好的解决以上问题。