一文走近JavaScript中的闭包

119 阅读3分钟

一文走近JavaScript中的闭包

在讲述闭包之前, 让我们先来看看MDN中是怎么解释闭包

闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment, 词法环境)的引用的组合. 换而言, 闭包让开发者可以从内部函数访问外部函数的作用域. 在 JavaScript 中, 闭包会随着函数的创建而被同时创建.

听起来略微有些抽象

让我们来书写一个较为经典闭包, 逐渐地理解它的含义


Example---认识闭包


// 代码一 

function a(){
    var i = 0;
    function b(){
        i++
    }
    b();
}

a() // i == 1 
a() // i == 1 
a() // i == 1 



// 代码二

function a(){
    var i = 0;
    function b(){
        i++;             // 此时函数a里面的函数b调用了外层函数
    }                    // 中声明的变量i, 这个时候我们就说
    return b;            // 函数b和变量i形成了一个闭包
}

var c = a(); 

c() // i == 1
c() // i == 2
c() // i == 3

其中代码一的逻辑是比较好理解的, 结果也在情理之中

而代码二为什么可以做到i始终在增加呢

让我们来梳理一下其中的逻辑

初始化函数a, 在a中声明了一个变量i

随后初始化函数b, 其作用是i自增

最后返回函数b

此刻再创建一个变量c, 来接受函数a的返回值(即函数b)

当我们调用c时, 我们实现i的自增

当我们再次调用时, i继续自增

其中与代码一不同的就是, 在函数c被调用后, i并没有被js的垃圾回收机制回收

而是继续保留了下来, 在后续继续完成了自增的工作


闭包的特征和为什么选择使用闭包

根据上面的案例我们可以发现

闭包有以下三个特征

  • 满足函数嵌套函数
  • 内部的函数使用了外部函数的参数和变量
  • 函数中的参数和变量不会被js的垃圾回收机制所回收

可能在这里就会产生疑惑了

闭包到底有什么用嘞, 这里直接使用全局变量不就好了吗


选择闭包的原因可以归纳为两点

  1. 全局变量容易造成重名, 进而发生变量污染
  2. 闭包在开发者能力范围内延长了变量的生命周期

看到这里, 相信现在你已经对闭包有了自己的一个认识

接下来让我们来闭包是如何贯彻我们学习js的道路

闭包的经典案例



// 返回值

function fn(){
    var name="hello";
    return function(){
        return name;
    }
}
var fnc = fn();
console.log(fnc()) // hello



// IIFE(自执行函数)

// 使用自执行函数构造一个私有的作用域, 从而弥补了js中没有私有变量的问题

var private = (()=>{
    name = 'private'
    sex = 'walmartBag'
    return {
        getName(){
            return name
        },
        getSex(){
            return sex
        }
    }
})()

console.log(private.getName())

console.log(private.getSex())


经典的案例还有很多, 我们就只说到这里, 如果还想了解更多的话可以来google


从闭包二字深入认识闭包

这是我在某个网站上看到某位佬写的, 分享给大家

闭包可分为"闭", "包"二字
"闭"即通过函数将其中的参数和变量封闭在一个作用域内, 外面无法直接访问
而"包"就是将它给打包, 分发给需要使用它的对象, 从而实现了生命周期的延长


闭包的缺点

虽然我们在上文用十分多的笔墨来写怎样实现闭包, 闭包有哪些好处

但是我们在使用闭包的时候要慎重

因为

变量并没有被回收, 会长时间的占据内存, 进而影响网页的性能(内存泄漏)



总结


万事万物皆有利有弊

代码世界也同样, 并不是非黑即白的

闭包在帮助我们延长变量生命周期的同时

也造成了内存泄漏

所以我们在使用它的时候需要好好地权衡权衡

ᕙ(`▿´)ᕗ

2023/5/19