关于闭包的理解,我不是说谁,我是说在读的大多数都错了

865 阅读4分钟

R-C.jfif

最近我对闭包进行了深入的研究,发现只要抓住关键点就能理解闭包的使用,进而快速分辨出是不是在使用闭包,于是就有了这篇文章,看完之后你会发现闭包的应用无处不在。

如果你还不知道闭包是什么?请移步# 闭包并不难:面试还在担心回答不出来闭包相关问题?

一,难懂的闭包

在各种文献上,"闭包"(closure)定义非常抽象,很难看懂,比如 MDN 和 《javascript 高级程序设计》。

MDN 上这样解释闭包

一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起
(或者说函数被引用包围),这样的组合就是闭包(closure)

高级程序设计第四版解释

 闭包指的是那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的。

难懂的概念导致每个人在学习过程中,感觉云里雾里,难以消化,经过痛苦的学习和实践后有了自己的理解。 至于理解的深度就依赖个人的学习过程。

二,闭包常见的理解思路

对于闭包的理解,大家通常主要有 2 种思路

1, 闭包是外部函数嵌套内部函数,并且内部函数使用了外部函数的变量,内部函数和那些使用的变量称为闭包

2, 闭包是外部函数嵌套内部函数,并且内部函数使用了外部函数的变量,内部函数称为闭包

上面思路并没有错。问题出在应用的时候,没法通过概念,直观的看出是不是形成了闭包? 为了检验你是不是能轻易的分辨出闭包,我列举几段代码,让大家判断是不是形成了闭包?

代码片段一

function foo() {
  const name = '掘金'

  const baz = function() {
    console.log(name)
  }

  bar(baz)
}

const bar = function(fn) {
  fn()
}

foo()

代码片段二

function foo() {
  const name = '掘金'

  setTimeout(() => {
    console.log(name)
  }, 1000)
}

foo()

代码片段三

function foo(fn) {
  const args1 = Array.from(arguments)
  args1.shift()
  return function(...args2) {
    return fn(...args1, ...args2)
  }
}

const add = foo((a, b) => a + b, 1)
add(1)

代码片段四

function foo() {
  const name = '掘金'

  const getName = function () {
    return name
  }

  return {
    getName
  }
}

const bar = foo()
bar.getName()

三,理解闭包的关键

首先,上面四段代码都能形成闭包。下面是代码片段一的注释版本。

function foo() { // 外部函数
  const name = '掘金'

  const baz = function() { // 内部函数
    console.log(name) // 使用外部函数变量
  }

  bar(baz) // baz 函数作为参数被传递出去了
}

const bar = function(fn) {
  fn() // 参数函数调用
}

foo()

这段代码符合闭包的定义,外部函数 foo 嵌套内部函数 baz,并且内部函数 baz 使用了外部函数 foo 的变量。那么它就是闭包吗?

你是不是不能完全肯定?总觉得少了点什么?我相信大多数人心里或多或少都会这样想。这篇文章就是来解救你的, 让我来告诉你闭包的关键吧。

看代码中的 baz 函数,它被作为参数传递给了 bar 函数, 在 bar 函数内部执行。当它执行的时候能使用 foo 函数中的 name 变量。之所以能使用 name 变量,是因为形成了闭包,name 被保存在了内存中。

其中的重点在于,内部函数 foo通过函数参数传递到了外部。核心关键词是传递。

后面 3 段代码都是不同方式传递的变种。代码片段二是通过回调函数传递,代码片段三是通过返回函数传递,代码片段四是通过返回对象方法传递, 所以都是闭包。

那么判断一段代码是否形成闭包的关键在于 内部函数如何传递到外部?

其实以上 4 段代码就是闭包的 4 种经典的传递内部函数的手段,如果还有其他常用方式请告诉我。

学会了如何判断是否形成闭包,去重新检查你的代码吧,你会发现很多地方都有使用闭包,闭包无处不在!

(本文完)