书中有悟:一文讲清楚闭包和作用域之间的关系!

前言

闭包(closure)对于大家来说应该已经不陌生了,但是当有人问你时,你真的能讲清楚什么是闭包吗?今天这篇文章通过结合红宝书黄宝书中对闭包的定义,来讲一下闭包词法作用域之间的关系及什么是真正意义上的闭包。

关键词: 闭包、词法作用域。

如何查看闭包

首先我们创建一个html文件在浏览器打开,运行一段生成闭包的js代码。

js 复制代码
function fn() {
  var name = 'lgh'
  function fn2() {
    console.log(name)
  }
  fn2()
}
fn()

这里以谷歌浏览器为例:F12打开控制台 > 点击Source标签 > Scope > closure。具体操作可看下图示例:

上图在第14行运行时可生成闭包,所以在此处打了个断点,运行到此处就会停下来,在右侧的Scope下的closure属性出可看到在执行fn2时,生成了一个涵盖fn函数作用域的闭包,闭包下包含对外层函数变量name的引用。

闭包的定义

下面是在这两本书中关于闭包的定义。

1.javascript高级程序设计: 闭包指的是那些引用了另一个函数作用域中变量的函数,通常是在嵌套中实现的。

2.你不知道的JavaScript: 当函数可以记住并访问所在词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。

从第二个定义来看 ,其实是不认同上面的例子是闭包的。更准确来说fn2函数对a的引用方法是词法作用域的查找规则,简单来说就是fn2函数是在fn函数的词法作用域中定义并执行了,并不是真正意义上的闭包,而只是闭包的一部分!而真正意义上的闭包应该在自己定义的词法作用域外执行。即以下这段代码才是真正的闭包:

js 复制代码
function fn() {
  var name = 'lgh'
  function fn2() {
    console.log(name)
  }
  return fn2;
}
const fn3 = fn()
fn3() // 输出:lgh

fn函数通过return返回fn2,并在fn函数的词法作用域外执行,并且访问到了fn函数内的变量name,这才应该是闭包的效果;而不是引用单纯的词法作用域查找就能访问的变量

这里也有一个容易理解的误区是只有函数内部返回一个引用了其内部作用域变量的函数才算是闭包。

参考以下例子其实也是闭包:

js 复制代码
// 函数传递
function fn2(cb) {
  cb() // 输出lgh。这也是闭包,在fn的词法作用域外执行了fn3
 }

 function fn() {
  var name = 'lgh'
  function fn3() {
    console.log(name)
  }
  fn2(fn3)
 }

 fn()
js 复制代码
// 变量赋值
 var fn

 function fn2() {
  var name = 'lgh'
  function fn3() {
    console.log(name)
  }
  fn = fn3  // 内部函数赋值给外部变量
 }

 function fn4() {
  fn() // 闭包
 }

 fn2() // 执行赋值操作
 fn4() // 生成闭包

闭包生成条件

闭包是在运行时生成的。闭包 是指一个函数对象,它不仅包含了函数的代码,还记录了函数创建时的环境信息,包括函数内部的变量、参数等。这些环境信息使得闭包可以在函数定义的作用域之外被调用,并且可以访问到其定义时的变量状态。

总结

闭包可以是那些引用了另一个函数作用域中变量的函数。但真正意义上的闭包是在定义它的词法作用域外执行才能发挥它的真正的效果,也是严格意义上的闭包!

相关推荐
BillKu33 分钟前
Element Plus 的 el-tab-pane:lazy 的说明
前端·javascript·vue.js
爱勇宝34 分钟前
《道德经》第 11 章:真正有用的,常常是你没写出来的那部分
前端·后端·产品
jearry37 分钟前
WebView2 原生拖放的桥接之道:拆解 yyzTools 的 drop-zone.js
前端·c++
一位正在转型AI全栈的前端工程师38 分钟前
AI 全栈学习之旅 -Week 11:从 CLI 到浏览器:用 FastAPI、SSE 和 Vue 3 做一个可审核的 ReAct Agent
前端·python
10share42 分钟前
我为什么用 React 重写了一个 VitePress
前端·react.js
计算机魔术师44 分钟前
GPT-6 Astra 发布后,Sebastian Raschka 解析 looped transformer 与隐藏推理链传闻
前端
不可能片场1 小时前
Electron 退化成 node:一个环境变量的锅
前端·electron
楚楚河河1 小时前
js 变量声明
前端
Cicada1281 小时前
Web 服务器怎么选
运维·服务器·前端
不可能片场1 小时前
接口返回 200 不代表活着:catch-all 路由的陷阱
前端·electron