JavaScript 重中之重的难点————闭包
一、作用域链:
首先推荐B站一个视频,视频从作用域链、生命周期、块级作用域、到闭包讲的十分全面:https://www.bilibili.com/video/BV1YJ411R7ap?p=3&spm_id_from=pageDriver&vd_source=452bb044f96afbbf26944f5c6904defd
现在开始,了解闭包之前必须要了解明白JavaScript作用域的划分。
1.作用域:变量和函数的可访问范围,控制着变量和函数的可见性与变量的作用范围。
2.全局作用域:网页中所有脚本和函数均可使用。
全局变量即拥有全局作用域的变量,即使页面没有调用使用,也不会被回收机制清除,而是继续存在于内存中,只有浏览器关闭时候才会清空。
3.局部作用域:只能在定义的函数内使用。
局部变量即在定义函数内可以调用使用的变量,函数调用结束之后就会清空,下次调用在重新开辟内存空间
举一个例子:定义两个变量 一个全局a 一个局部b。
可以根据结果看出,在全局环境中如果调用输出局部变量会报错:子用父可以,父用子不行。
在举一个新例子:嵌套函数 更加深层次嵌套,如果想要输出b的累加
根据结果可以清除看到,局部变量b每次都要重新开辟内存空间,之前的b就被回收删除了。
那么现在想实现一次b的累加 如何做到,如果可以让b每次都不清空,保存在内存之中不动,跳过重新开辟内存这一步骤,是不是就可以完成累加。
如果在全局中设定一个变量,用来存放xx()一直调用,那么回收机制就不会触发,也就不会重新开辟内存。
而经过ax调用yy(),同级变量b并不会被清空销毁,而是同时保存在内存中。即这就是闭包。
二、闭包:
1.定义:闭包函数是声明在另一个函数内的函数,是被嵌套在父函数内部的子函数。
而在《JS高级程序设计-第3版》中对闭包解释是:”闭包是指有权访问另外一个函数作用域中的变量的函数.” 闭包函数可以访问[包裹其的函数]内的各种参数和变量,即便外部函数已经执行完毕。
看不懂太乱对不对。那么就用人话解释一下。函数可以访问其他函数内的变量就称为闭包。
上述例子当中,子函数yy() 可以访问父级函数当中变量b,即为闭包特性之一。
2.闭包作用:
-
- 使外部得以访问函数内部的变量;
- 避免全局变量的使用,防止全局变量污染
- 让某些关键变量得以常驻内存,免于被回收销毁
3.闭包缺点:由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
4.闭包应用:使用场景 : 防抖、节流、函数套函数避免全局污染等。
三、闭包应用场景:
1.获取区间:例如在一串数组中获取一个区间之间的数字。
其原理正是闭包原理。内部子函数可以调用外部父函数between内部的变量a和b。也可以应用到商品价格区间等。
2.防抖:防抖是经常出现在js动画中的概念,好多萌新都不了解什么是防抖。其实顾名思义防止抖动。那么为什么动画会出现抖动?
假设现在制作一个动画,一个按钮点击之后就缓慢向右移动。代码如下,可以很简单的实现效果
但现在存在一个问题,如果点击多次按钮,就会出现按钮抖动(原谅我截图没办法体现抖动的状态。)就好像花屏一样。那么为什么会出现这种情况?
首先,当你点击一次按钮,触发了事件之后,已经在内存当中开辟了一块区域让你存放。但是当你点击第二次,由于 left 是局部,所以还会开辟第二块区域。结果每次点击都产生新的left 就会造成抖动效果。
那么如何避免,就像上面提到如何累加的案例一样,如果让left不在重新产生,而是一直存放在内存中,就可以完美解决了。
最简单的办法就是,将left设置为全局属性,这样就一直存放在内存中。
随之而来就出现另一个问题,当你再次连续点击按钮,虽然不会出现抖动效果,但是会产生按钮加速向前的效果。这是因为每次点击按钮,都产生一个定时器,而left 变成全局之后,定时器就变成了一个类似于叠加的效果,所以导致动画加速。那么就要将定时器设定为,只有第一次才会触发,直到动画结束。添加一个全局变量,在通过if判断。
但是变量都设定为全局会导致,全局变量污染,加剧内存负担。所以就可以将left 放入 判断里面。
四、总结:
讲的可能不是特别全面,个人自身也是萌新小白,只能慢慢摸索去学,希望大家都比昨天的自己进步一点。
原创文章,作者:Carrie001128,如若转载,请注明出处:https://blog.ytso.com/tech/webdev/272966.html