#yyds干货盘点# 详解JavaScript中的闭包

Posted 啊a阿花

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#yyds干货盘点# 详解JavaScript中的闭包相关的知识,希望对你有一定的参考价值。

一、作用域环境

  1. 在js作用域环境中访问变量是由内向外的,内部作用域可以获得当前作用域下的变量,和当前作用域外层作用域下的变量
  2. 外层作用域无法访问内部函数的变量
  3. 不同的函数作用域中不能相互访问彼此间的变量

二、闭包的作用

如果我们想在一个函数内部也有限权访问另一个函数内部的变量,那么就可以使用闭包,闭包的本质就是在一个函数内部去创建另一个函数。

三、闭包的体现

1、将函数作为返回值

function fn()
    let a = 1
    return function ()
        let b = 1
        console.log(a:,++a)
        console.log(b:,++b)
    


let f = fn()
f()  // 2  2
f()  // 3  2

这段代码的意思是,将fn的返回值(一个匿名函数)赋给f,f()表示调用fn()返回的匿名函数。

为什么第二次调用a和b的值不一样?

利用闭包的特性保存变量

例:在for循环中每隔0.5秒打印出当前循环的次数

错误解法

        for(var i = 0; i < 5; ++i )
                setTimeout(()=>
                    console.log(i)
                ,500)
        

你会发现控制台直接输出了5个5

因为js代码执行时有一个任务队列,for循环属于微任务,setTimeout属于宏任务,宏任务会等到微任务执行完毕才会进入javascript的调用栈。具体细节推荐阅读这篇文章:一篇文章快速搞懂JavaScript事件循环、任务队列、同步异步和阻塞非阻塞

也就是说等setTimeout执行时for循环已经执行完毕了,此时i=5,所以输出了5个5

正确解法

for(var i = 0; i < 5;++i )
    (function(i)
        setTimeout(()=>
            console.log(i)
        ,i*500)
    (i))

// for循环里面是一个立即执行函数,最后面的‘(i)’表示往这个立即执行函数里面传递的参数
  1. 将setTimeout放进立即执行函数里面,利用闭包存储每次循环时变量i的值
  2. 然后再将每个定时器设置不同的时间,这样就相当于每一次循环开一个定时器,每个定时器之间相差500毫秒,实现每隔500毫秒输出一次

es6中的写法
使用let定义变量i

  for(let i = 0; i < 5; ++i )
     setTimeout(()=>
         console.log(i)
     ,500)
  

var定义的i在全局范围内都有效,所以全局只有一个变量i。每一次循环,变量i的值都会发生改变,但是里面的i,指向的都是同一个i,导致运行时输出的是最后一轮的i的值,也就是 5

es6中引入了let,变量i是let声明的,具有块级作用域,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,JavaScript 引擎内部会记住上一轮循环的值,在上一轮循环的基础上进行计算然后初始化本轮的变量i

不过,虽然能顺序输出12345,他们也并不是间隔500毫秒,而是一起输出的。因为let虽然能记住每一次的变量,但是setTimeou的执行顺序不会改变

2、将函数作为参数

        var num = 1
        var fn = function(a)
            if(a > num)
                console.log(a)
            else(
                console.log(num)
            )
        

        function fn1(fn2)
            var num = 10
            fn2(5)
        

        fn1(fn)

这段代码会输出5,因为fn被作为参数传入到fn1中,当执行fn2(5)时(fn2(5)相当于fn(5)),5作为参数传入fn中,这时if(a&gt;num)中的num是当前函数作用域下的num,也就是全局作用域下的num = 1 ,而不是fn1中的num = 10

所以 5>1,控制台输出5

四、闭包的优缺点

优点

  1. 形成私有的执行上下文,使内部私有变量不受外界干扰
  2. 避免命名冲突
  3. 解决循环绑定引发的索引问题

缺点

变量不会被垃圾回收机制回收、销毁,导致内存泄漏

以上是关于#yyds干货盘点# 详解JavaScript中的闭包的主要内容,如果未能解决你的问题,请参考以下文章

[Flutter]专题Flutter 中的 AppBar详解#yyds干货盘点#

Tomcat详解#yyds干货盘点#

# yyds干货盘点 # 盘点JavaScript中的事件及事件的三种模型

#yyds干货盘点#什么是JavaScript 中的函数劫持

#yyds干货盘点# Java 基础 - 反射机制详解

#yyds干货盘点#JavaScript数值范围