JavaScript中的闭包逻辑

根据js词法作用域的规则,内部函数总是能访问外部函数中的变量, 当通过一个外部函数返回的一个内部函数后,即使外部函数执行已经结束了,但是内部函数引用了外部函数中的变量, 也依旧需要被保存在内存中,我们把这些变量的集合叫做闭包

在学习「闭包」之前,得先了解一下js引擎的运行顺序

作用域链

  1. 函数在执行前预编译,会创建执行上下文对象
  2. 变量环境中有一个内定的outer属性用于指明该函数的外层作用域是谁
  3. 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还需要访问他的countage数据,这个时候就产生了闭包。
  • 即使外部函数执行已经结束了,但是内部函数引用了外部函数中的变量,也依旧需要被保存在内存中。

图片

而这题和上一题有所不同,barfoo内部,因此barouter指向的是foo而不是全局

图片

「得到答案“1,19”」

小小闭包大大用处

1. 实现共有变量:

在实现模块化开发中非常有用,尤其是在需要共享变量或状态时。在企业级应用开发中,模块化可以带来代码的可维护性、可重用性和可测试性

2. 做缓存:

也可以称作记忆化,作为一种优化技术,用于存储操作的结果,以便在下次执行相同操作时可以快速返回结果,而不是重新计算。

3. 封装模块:

闭包可以用来创建模块化的代码,通过封装私有变量和函数,可以避免全局变量的污染,使得代码更加清晰和易于维护。

闭包虽然提供了强大的功能,但它也有一些缺点

  1. 「内存消耗」:闭包会持久化其作用域内的变量,即使这些变量在外部函数执行完毕也依然被保存,这会导致内存消耗增加。如果不正确管理,可能会导致内存泄漏。
  2. 「性能影响」:在某些情况下,使用闭包可能会对性能产生负面影响。

总结

闭包是JavaScript中的一种强大工具,它提供了数据封装、模块化、状态管理等多种功能。不过开发者在使用闭包时需要注意其可能带来的内存消耗、性能影响和可维护性问题。 在实际开发中,应该权衡闭包的利弊,并根据具体情况做出适当的选择。正确理解和使用闭包,可以帮助开发者编写出更加高效、可维护的代码。

原创文章,作者:guozi,如若转载,请注明出处:https://www.sudun.com/ask/79492.html

Like (0)
guozi的头像guozi
Previous 2024年5月30日 下午6:49
Next 2024年5月30日

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注