根据js词法作用域的规则,内部函数总是能访问外部函数中的变量, 当通过一个外部函数返回的一个内部函数后,即使外部函数执行已经结束了,但是内部函数引用了外部函数中的变量, 也依旧需要被保存在内存中,我们把这些变量的集合叫做闭包
❞
在学习「闭包」之前,得先了解一下js引擎的运行顺序
作用域链
- 函数在执行前预编译,会创建执行上下文对象
- 变量环境中有一个内定的
outer
属性用于指明该函数的外层作用域是谁 outer
的指向是根据词法作用域来定的
❝
- js引擎在查找变量时,会先在函数在查找,找不到会根据outer的指向去到外层作用域中查找, 层层往上,这种查找的关系链就称为 作用域链
❞
function bar () {
console.log(a);
}
function foo () {
var a = 100;
bar()
}
var a = 200
foo()
对于上面这段代码,先进行预编程得到如下图的栈
❝
- 于是很多人可以一眼看出,输出的时a = 100,但是结果是错误的,正确答案是200
- 这里就得带入outer,outer属性指向该函数的外层作用域
❞
「函数bar是作用在全局作用域中,因此bar的outer指向的是全局变量环境,输出的值就为200」
词法作用域
- 一个域所处的环境,是由函数声明的位置决定的
开展介绍闭包的形成
function foo(){
function bar(){
console.log(count,age);
}
var count = 1
var age = 19
return bar
}
var age = 20
const baz = foo()
baz()
看到这绕来绕去的代码还是先画个图来分析一下
- 我们都知道,在函数运行结束之后为了减少缓存会自动将函数的内容删除,这里
foo
函数运行完了就应该被删除,但是在foo
内部的函数bar
还需要访问他的count
和age
数据,这个时候就产生了闭包。 - 即使外部函数执行已经结束了,但是内部函数引用了外部函数中的变量,也依旧需要被保存在内存中。
而这题和上一题有所不同,bar
在foo
内部,因此bar
的outer
指向的是foo
而不是全局
「得到答案“1,19”」
小小闭包大大用处
1. 实现共有变量:
在实现模块化开发中非常有用,尤其是在需要共享变量或状态时。在企业级应用开发中,模块化可以带来代码的可维护性、可重用性和可测试性
2. 做缓存:
也可以称作记忆化,作为一种优化技术,用于存储操作的结果,以便在下次执行相同操作时可以快速返回结果,而不是重新计算。
3. 封装模块:
闭包可以用来创建模块化的代码,通过封装私有变量和函数,可以避免全局变量的污染,使得代码更加清晰和易于维护。
闭包虽然提供了强大的功能,但它也有一些缺点
- 「内存消耗」:闭包会持久化其作用域内的变量,即使这些变量在外部函数执行完毕也依然被保存,这会导致内存消耗增加。如果不正确管理,可能会导致内存泄漏。
- 「性能影响」:在某些情况下,使用闭包可能会对性能产生负面影响。
总结
闭包是JavaScript中的一种强大工具,它提供了数据封装、模块化、状态管理等多种功能。不过开发者在使用闭包时需要注意其可能带来的内存消耗、性能影响和可维护性问题。 在实际开发中,应该权衡闭包的利弊,并根据具体情况做出适当的选择。正确理解和使用闭包,可以帮助开发者编写出更加高效、可维护的代码。
原创文章,作者:guozi,如若转载,请注明出处:https://www.sudun.com/ask/79492.html