JS理解:立即执行函数为什么是闭包?

728 阅读3分钟

首先看下产生闭包的2种典型的过程:

  • 立即执行函数
(function IIFE() {
  console.log(666)
})()
  • 函数被当成值传递
function f1() {
  var a = 1
  function f2() {
    console.log(a)
  }
  return f2
}
var func = f1()
func()

我们可以从这几个角度分析这两个过程的共性:作用域,函数定义,(函数传递),函数执行。

先看第一个立即执行函数,第一个括号(function IIFE() {console.log(666)}) ,这个括号的意义是在于让里面的函数,直接返回,举个例子,在箭头函数中

const af1 = () => {}    //直接使用{},里面的就是代码块,无返回
const af2 = () => ({})    //而如果加了()就会 直接返回 一个空对象{}

所以对于立即执行函数而言,它定义的同时就直接返回了,也就是说它是在返回中定义的,而执行时候是在全局作用域的,说明它定义和执行是在不同的作用域

再看下第二个闭包例子:f2 是在 f1 的函数作用域里定义的,执行时: 先执行f1,f1返回f2后,在全局作用域中执行f2。说明这个函数的定义和执行也是在不同的作用域。

那么为什么会在不同的作用域呢?答案是他们都被传递了。只不过立即执行函数是被隐式的传递了,(function IIFE() {console.log(666)}) 返回的过程就是传递。我们可以改造下第二个例子。

function f1() {
  var a = 1
  return function f2() {
    console.log(a)
  }
}
f1()() //  执行f1 返回f2 ,再执行f2

几乎和第一个例子一模一样,都是返回一个函数再执行。

这就是闭包最大秘密:传递。简而言之,函数被传递其他作用域执行,就会产生闭包。用这个标准可以去分析所有的闭包。注意,我们是从函数行为和过程去定义的闭包。那从结果上如何定义呢?能够读取其他函数内部变量的函数特性。闭包是一个动态的过程,是函数执行过程中所展示出来的一种特性。

总结一下,闭包就是:函数被传递到其他作用域后执行,仍保持对其定义时作用域的访问的过程。 网上之所以对闭包的定义众说纷纭,是因为有的重过程,有的重结果,所以对于初学者很容易产生误解。

再看下书上对于闭包的定义:函数可以记住并访问定义时所在的词法作用域,即使函数在当前词法作用域之外执行,这时就产生了闭包。前面这个访问,说明了闭包产生的结果。即使后面是说闭包产生的过程。

最后注意一下,传递的方式有很多种,函数的返回只是传递的一种方式,例如,我们平时在react中父子组件通信时,在父组件中通过属性传递函数,然后在子组件中调用,也是闭包应用的体现。