首页前端开发正文

如何理解JS里的“闭包”?

朱绪2021-01-011624JavaScript

今天逛知乎,无意间看到一篇关于“闭包”的文章,感觉写得蛮不错,所以打算转载到博客里。

作者:方应杭,原文地址:https://zhuanlan.zhihu.com/p/22486908

原文如下:(为了增加阅读体验,我对原文略有修改)

可以这么说,“闭包”问题是前端面试必问的!

比如,请用自己的语言简述:

  1. 什么是闭包。

  2. “闭包”的作用又是什么?

我先来简述一下什么是闭包:

闭包

假设上面三行代码在一个立即执行函数中(为了更简化,我就不写立即执行函数了,影响读者理解)。

三行代码中,有一个局部变量local,有一个函数foo,foo里面可以访问到local变量。

ok,这就是一个闭包:

“函数”和“函数内部能访问到的变量”的总和,就是一个闭包。

就这么简单。

看到这儿,有的同学就会疑惑了,闭包这么简单的么?“我听说闭包是需要函数套函数,然后return一个函数的呀!”

比如这样:

function foo(){
    var local = 1
    function bar(){
        local++
        return local
    }
    return bar
}
var func = foo()
func()

这里面确实有闭包,local变量和bar函数就组成了一个闭包(Closure)。

为什么要函数套函数

是因为需要局部变量,所以才把local放在一个函数里,倘若不把local放在一个函数里,很显然local就是个全局变量了,达不到使用闭包的目的——隐藏变量(等会会讲)

这也是为什么我上面要说“运行在一个立即执行函数中”。

有些人看到“闭包”这个名称,就觉得一定要用什么包起来才行。其实这是翻译的问题,闭包的原文是Closure,跟包没有任何关系。

所以说,函数套函数只是为了造出一个局部变量,跟闭包无关。

为什么要return bar 呢?

因为如果不return,你就没法使用这个闭包。把return bar 改成window.bar = bar也是一样的,只要外面能访问到这个bar函数就行。

所以,return bar只是为了bar能被使用,也跟闭包无关。

闭包的作用

闭包常常用来“间接访问一个变量”。换句话说,“隐藏一个变量”。

举个例子吧,假设我们在做一个游戏,在写其中关于“还剩几条命”的代码。

如果不用闭包,你可以直接用一个全局变量:

window.lives = 30   //还有30条命

这样看起来很不妥。万一不小心把这个值改成-1了怎么办。因此我们不能让别人“直接访问”这个变量。这该如何是好呢?

用局部变量。

但是用局部变量别人又访问不到,该怎么办?

暴露一个访问器(函数),让别人可以“间接访问”。

代码如下:

!function(){
    var lives = 50
    window.奖励一条命 = function(){
        lives += 1
    }
    window.死一条命 = function(){
        live -= 1
    }
}()

为了看起来更直观,我用了中文。

那么在其他的JS文件,就可以使用window.奖励一条命()来涨命,用window.死一条命()来让角色掉一条命。

看到闭包在哪儿了吗?

如何理解JS里的“闭包”