面对面试题,我们总是如临大敌。可恶的面试题前段时间有个面试,工程组让我解释一下闭包是什么意思。诚然,这不是我第一次被问及这个词,但老实说,我还是有点慌张。我们都知道术语闭包因难以定义而臭名昭著。面试结束后,我很沮丧,因为我仍然害怕这个问题。我下定决心要彻底理解闭包的含义。这个博客将带您了解我的经验。匿名函数和IIFE不是闭包在本文开始之前,让我澄清一下不涉及的内容。在ES6之前的时代,闭包的一个常见用例是匿名函数/IIFE(立即调用的函数表达式),用于模拟并非JavaScript独有的私有方法。这个和其他由var的限制引起的类似用例在很大程度上是通过在ES6中引入let、const和模块来解决的。IIFE包括闭包,但不是闭包。匿名函数也不是闭包。anonymousFunc!==closure&&IIFE!==closure//true学习这些用例很重要。如果您了解闭包在过去是如何使用的,那么您就可以了解它们今天是如何使用的。更不用说还有很多ES5遗留代码。但这不是我今天要谈的内容。解释完了,我们就深入了解一下。闭包概念的起源:Pexels在计算机科学中,闭包是一种函数,它有自己的环境,并且在该环境中至少有一个变量。MDN指出:“在JavaScript中,无论何时创建一个函数,都会创建一个闭包。”因此,函数和闭包是密切相关的。每次创建函数时,您都在构建一个闭包,这意味着您可能一直在创建它们而没有意识到。MDN继续指出“闭包是一种组合(封装),它将函数与其引用的周围状态绑定在一起”,这将我们带到了范围。它与范围有什么关系?从前面的引用中更深入地探索术语周围状态。在JavaScript函数中,周围的状态称为作用域。创建JS文件时,环境是程序的全局范围。创建函数时,它有自己的作用域。将全局范围视为状态。一个国家有许多城市,每个城市都在自己的边界内。同样,在程序的特定部分,我们发现对象包含在本地范围内。Javascript有两个局部作用域:函数作用域和块作用域。functionencourage(){constpositivity='Yougotthis!';}//positivityhasfunctionscope{constnegativity='Idon'tgotthis.';}//negativityhasblockscope函数存在并且可以访问全局作用域,但是函数内部声明的任何东西都只存在于And中只能访问函数范围,不能访问全局范围。同样,如果您在代码中的任何位置将变量括在花括号中,该变量也将被括起来并属于块级范围。闭包和作用域将闭包理解为封装函数的感官门可能更容易。例如,当创建一个新函数时,该函数的闭包会环顾四周并记下它的环境,即作用域。functionhighestBoxOffice(){constcontext="Thehighestgrossingmovieofalltimeis";returncontext+"Avengers:Endgame";}即使该函数没有子函数,它仍然有闭包。闭包不仅仅存在于嵌套函数中。在变量上下文的情况下,函数的闭包环顾四周并在内部找到变量。Closuresinnestedfunctions来源:Pexels如果你创建一个嵌套函数,那个函数的闭包会找到它所在的父函数的墙。父函数的作用域是嵌套函数的外部作用域,包括函数中的变量父函数。functionhighestBoxOffice(movies){returnfunctiongenreTopGross(genre){returnMath.Max(...movi??es.genre.boxOffice)}}这是闭包真正发挥作用的地方。函数genreTopGross()有一个闭包。它的闭包向内查找以找到其内部范围,其中包含returnMath.Max(...movi??es.genre.boxOffice)。它还查看外部并找到其外部范围,并在函数highestBoxOffice()中对其进行标记。它还可以查看和访问传递给其父函数的所有参数。现在传递一个参数。functionhighestBoxOffice(movies){returnfunctiongenreTopGross(genre){returnMath.Max(...movi??es[genre].boxOffice)}}consttopGrossing=highestBoxOffice(domesticMoviesObj)如您所见,已声明并分配了一个新变量topGrossing()最高BoxOffice(domesticMoviesObj)值。目前,topGrossing未定义,但现在执行下一步:RomanticComedy")//"PrettyWoman"引用topGrossing()并将"RomanticComedy"作为参数传递。现在显示了闭包的用处!genreTopGross()函数的内部作用域需要movies参数,该参数位于domesticMoviesObj参数的外部作用域,需要通过闭包进入。这使得代码成功执行并返回它正在寻找的值。闭包和范围链在JavaScript中,每个变量在首次创建时都属于特定的词法范围。在编写的程序中,每个变量的作用域都由作用域链连接,全局作用域始终位于链的顶部。JavaScript编译器遍历这条链。然而,编译器就像一辆汽车,只会倒退,不会前进。当使用一个变量时,编译器返回作用域链,直到找到该变量的条目。因此,当genreTopGross()函数使用电影变量时,JavaScript不会在genreTopGross()范围内找到电影。因此,JavaScript向上移动作用域链,直到找到传递给highestBoxOffice()的电影。这与闭包有什么关系?闭包只提供从内部作用域到外部作用域的访问,而不是从外部作用域到内部作用域的访问。因此,如果一个变量在几个嵌套函数中声明和定义,但在父函数的外部范围内使用,编译器将返回未定义的错误。请记住,汽车只会朝相反的方向行驶。结论来源:Pexels如您所见,理解闭包需要对函数、作用域和作用域链有扎实的理解,而这正是面试官提问时所寻求的。本文仅解释闭包的定义,并未涉及其众多用例。如果您了解这一点,您应该能够更深入地研究这些用例而不会感到完全迷失。如果没有其他问题,希望这篇文章能够提供一个简单的基础或者简洁的概述,让大家不再对闭包感到恐慌。现在,去接受采访吧!哦对~
