22

​一个基本的面试问题:可以解释一下什么是闭包吗?

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzI2NjkyNDQ3Mw%3D%3D&%3Bmid=2247492516&%3Bidx=1&%3Bsn=429b16ea69c1f8cf965f7530337eee75
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

EjyQZvZ.jpg!web

全文共 3379 字,预计学习时长 10 分钟

VJzU7b7.jpg!web

来源:Pexels

面对面试问题,我们总是如临大敌。

令人憎恶的面试问题

之前,我参加了一个面试,其中工程团队要求我解释闭包的含义。 当然,这不是我第一次被问到这个术语,但老实说,我还是有些慌张。

众所周知,闭包这个术语因难以定义而臭名昭著。

面试后,我对自己仍恐惧这个问题感到沮丧。 我下定决心,要彻底弄明白闭包的含义。 本篇博客将带领大家来看看我的经历。

匿名函数和IIFE不是闭包

文章开始前,我先阐明不会涉及的内容。 在ES6之前的时代,闭包的常见用例是用于模仿私有方法的匿名函数/ IIFE(立即调用函数表达式),这些方法不是JavaScript所特有的。

通过在ES6中引入let 、const的引入和以及模块,很大程度上解决了var 的局限性所导致的这种情况和其他类似的用例。 IIFE包括闭包,但不是闭包。

匿名函数也不是闭包。

anonymousFunc !== closure&& IIFE !== closure // true

学习这些用例很重要。 如果你理解过去使用闭包的方式,就能理解现在如何使用闭包。

更别说还有许多ES5遗留代码。 但是这不是今天要讲述的内容。 既然已经说明,那一起来深入了解吧。

闭包的概念

2mAJbaF.jpg!web

来源:Pexels

在计算机科学中,闭包是一个有自己环境的函数,,并且在该环境中至少有一个变量。 MDN指出:

“在JavaScript中,每当创建一个函数,闭包便产生。

因此,函数和闭包是紧密联系的。 每创建一个函数,都在构建一个闭包,这意味着你可能一直在创建它们,只是自己没有意识到而已。 MDN继续指出:

“闭包是将函数与其引用的周边状态绑定在一起形成(封装)的组合”

这将我们带到了作用域。

它与作用域有什么关系?

从前面的引用中更加深入地去探究周围状态这个术语。 在JavaScript函数中,周围状态称为作用域。

创建JS文件时,环境就是程序的全局作用域。 创建函数时,它有自己的作用域。

可以把全局作用域视为国家。 一个国家有许多城市,每个城市都封闭在自己的边界线内。 同样地,在程序的特定部分中,我们会发现包含在局部作用域内的对象。

Javascript有两个局部作用域: 函数作用域和块级作用域。

<span>functionencourage() {</span>

<span> <span>const</span> positivity =<span>'You got this!'</span>;</span>

<span>}</span>

<span><span>// positivity has function scope</span></span>

<span>{</span>

<span> <span>const</span> negativity =<span>'I don'</span>t got <span>this</span><span>.'</span>;</span>

<span>}</span>

<span><span>// negativity has block scope</span></span>

viewraw encourage.js  hostedwith ❤by  GitHub

函数存在于并能访问全局作用域,但是在函数内声明的任何内容仅存在于并只能访问函数作用域,而非全局作用域。

同样地,如果在代码的任何位置用大括号括起一个变量,那么该变量也将被封闭,属于块级作用域。

闭包和作用域

将闭包视为封闭函数的传感门可能更容易理解。 例如,创建新函数时,该函数的闭包到处查看并记下它的环境,即作用域。

function highestBoxOffice() {

const context = “The highest grossingmovie of all time is “;

return context + “Avengers:Endgame”;

}

即使函数没有子函数,它仍然有闭包。 闭包并不仅存在于嵌套函数中。 在变量context的案例中,该函数的闭包到处察看并发现其中存在变量。

嵌套函数中的闭包

aU36Vj3.jpg!web

来源:Pexels

如果创建一个嵌套函数,该函数的闭包发现它所在的父函数的墙壁。 父函数的作用域是嵌套函数的外部作用域,包括父函数中的变量。

functionhighestBoxOffice(movies) {

returnfunctiongenreTopGross(genre) {

returnMath.Max(…movies.genre.boxOffice)

}

}

viewraw highestBoxOffice.js  hostedwith ❤by  GitHub

这是闭包真正发挥作用的地方。 函数 genreTopGross()含有闭包。 其闭包向内看,发现其内部作用域,包含returnMath.Max(…movies.genre.boxOffice)。

它也向外看,发现其外部作用域,标志着它在函数highestBoxOffice()中。 它还可以查看并访问传递到其父函数的所有参数。 现在来传递一个参数。

functionhighestBoxOffice(movies) {

returnfunctiongenreTopGross(genre) {

returnMath.Max(…movies[genre].boxOffice)

}

}

const topGrossing =highestBoxOffice(domesticMoviesObj)

viewraw highestBoxOffice.js  hostedwith ❤by  GitHub

如你所见,已经声明了一个新变量topGrossing()并且赋予它highestBoxOffice(domesticMoviesObj)的值。

目前,topGrossing是未定义的,但是现在采取下一步:

functionhighestBoxOffice(movies) {

returnfunctiongenreTopGross(genre) {

returnMath.Max(…movies[genre].boxOffice)

}

}

const topGrossing =highestBoxOffice(domesticMoviesObj)

topGrossing("Romantic Comedy")// "Pretty Woman"

viewraw highestBoxOffice.js  hostedwith ❤by  GitHub

引用topGrossing(),并将“Romantic Comedy”作为参数进行传递。 现在闭包的用处展现出来了!

. genreTopGross()函数的内部作用域需要movies参数,该参数位于domesticMoviesObj参数的外部作用域,需要通过闭包来进入。

这使代码成功执行并返回正在寻找的值。

闭包和作用域链

在JavaScript中,每个变量在首次创建时,都属于一个特定的词法作用域。

在书面程序内,每个变量的作用域都通过作用域链连接起来,全局作用域总是位于该链的顶端。

JavaScript编译器遍历这条链。 然而,该编译器就像汽车,仅逆向运行,从不正向运行。

使用变量时,编译器返回到作用域链,直到找出该变量的入口。

因此,genreTopGross()函数使用movies变量时,JavaScript没有在genreTopGross()作用域中发现 movies。 所以,JavaScript沿着在作用域链中向上移动,直到找到传递到highestBoxOffice()的movies。

这与闭包有什么关系呢?

闭包只提供从内部到外部作用域的访问,而不能提供从外部到内部作用域的访问。

因此,如果在几个嵌套函数中声明并定义一个变量,却在父函数的外部作用域中使用,编译器将返回一个未定义的错误。 记住,汽车只会逆向行驶。

结论

22QjAvm.jpg!web

来源:Pexels

如你所见,理解闭包需要对函数、作用域以及作用域链有着扎实深入的理解,这正是面试者提问时所期待的。

本文只解释了闭包的定义,但并未涉及它们的大量用例。 如果您理解了这一点,应该能更深入地研究这些用例,而不会感到完全迷失。

若没有其他问题,希望本文能够提供简单的基础或简明的概述,使大家不再对闭包感到惊慌。

现在,去拿下面试吧! 哦耶~

UZbAzej.jpg!web

推荐阅读专题

mMby2iU.jpg!web

iYjIniQ.jpg!web

IjUZ322.jpg!web

jmyiMne.jpg!web

Nbqmy26.jpg!web

留言点赞发个朋友圈

我们一起分享AI学习与发展的干货

编译组: 王小燕、贺宇

相关链接:

https://medium.com/better-programming/a-basic-interview-question-can-you-explain-what-a-closure-is-710b75384d48

如转载,请后台留言,遵守转载规范

推荐文章阅读

ACL2018论文集50篇解读

EMNLP2017论文集28篇论文解读

2018年AI三大顶会中国学术成果全链接

ACL2017论文集:34篇解读干货全在这里

10篇AAAI2017经典论文回顾

长按识别二维码可添加关注

读芯君爱你

2ABbUry.gif


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK