当前位置: 首页 > Web前端 > JavaScript

闭包是什么,有什么用

时间:2023-03-27 15:17:18 JavaScript

这是我上个月面试遇到的一道面试题。作为一个拥有十年开发经验,七年前端经验的大龄青年,能遇到这种毫无伏笔的八卦文,真的是太神奇了。我只想说一个毁灭的词。记得刚做前端的时候,在百度上搜索闭包。我发现的大部分结果都是关于闭包的样子。比如函数内部的变量可以在函数外部访问,或者闭包会造成什么问题,比如影响GC回收。总之,没有一个标准的说法,就像现在网上的吐槽,面试题你背了也没用,得和面试官背同一套,天知道面试官学的是哪一套。《JavaScript高级程序设计》作为前端的必读书籍,是比较认可的认真的学习之路。它给出了闭包的以下定义:闭包是引用另一个函数范围内的变量的函数,通常在嵌套函数中实现。这里有两个关键字:范围和功能。众所周知,在JS中声明一个函数,会在函数内部形成一个新的作用域。在这个作用域中,可以访问包含函数声明的外部作用域中的变量和函数,形成一个作用域链,但通常在这种情况下,外部不能访问这个函数作用域内部的变量和函数。执行函数时,从作用域链中查找变量以读取和写入值。当每个函数执行时,它的执行上下文都会有一个包含变量的对象。全局上下文中的变量对象在代码执行过程中会一直存在;函数局部上下文中的活动对象仅在函数执行期间存在。作用域链实际上是一个指针列表,每个指针指向一个变量对象。例如:functioncompare(value1,value2){if(value1value2){返回1;}否则{返回0;}}letresult=compare(5,10);定义compare()函数时,为其创建作用域链,预加载全局变量对象,并存储在内部[[Scope]]中;当compare()函数被调用时,对应的执行上下文,然后通过复制函数的[[Scope]]创建其作用域链;然后创建函数的活动对象(用作变量对象)并将其推入作用域链的前端。函数执行后,局部活动对象被销毁,内部作用域被销毁,内存中只剩下全局作用域。闭包创建异常,使得函数内部的变量也可以在函数范围之外访问。这是因为函数内部变量的引用通过某种方式暴露给了外部(比如函数的返回值),并且在函数外部也有对其内部变量的引用,即有引用到函数外部的函数内部作用域,使作用域在函数执行后不能被销毁。这会影响内存回收,并可能导致内存泄漏,所以建议只有在绝对必要的时候才使用它。闭包示例:setTimeout(()=>console.log(value*2),1000);前置知识,函数的参数也存在于函数的内部作用域中。这里调用了setTimeout定时器方法,它的第一个参数是一个函数(或者是一个可以通过eval转成函数的字符串)。这个函数的实际执行是在浏览器运行时,所以在setTimeout之外有对这个函数的引用,也就是在setTimeout之外有对它内部作用域的引用,并产生一个闭包。当这个函数出队执行时,setTimeout的作用域链将被销毁。虽然闭包有其缺点,但也有可以利用的地方。防止变量溢出和全局污染在前端开发中,经常会用到一些第三方库,容易与业务代码产生冲突。这时候第三方库可以使用立即执行函数(IIFE),通过函数返回必要的变量。或者挂在某个特定的全局变量上,对外暴露,其他内部变量不会被访问,不会和业务代码冲突;这在团队协作中也很有用,可以防止与其他人的代码发生冲突,这是必要的冲突。访问私有变量有时候我们想把代码标准化,把相关业务的代码放在一起。这时候就可以通过函数将这些代码进行组装,使得这部分代码的可变数据不能被外界轻易修改,保证了数据的安全性。.但有时我们需要访问内部私有变量。这时候我们可以创建一个可以访问函数私有变量/函数的public方法,将这个方法的引用暴露出来,形成一个闭包,达到访问内部私有变量的目的。创建模块是访问私有变量的扩展使用。一个模块通常用一个对象来表示,对象是一些变量和一些函数的集合,通过对象的属性来访问这些变量和函数。模块中可能会有一些初始化操作,以及一些不想暴露给外部的私有变量/函数,可以通过立即执行函数的方式,将这些操作和变量/函数限制在内部范围内,之后返回一个模块对象执行,在这个对象中可以暴露一些公共属性和公共方法。