【JavaScript】一篇文章,带你拿捏闭包

一. 前言

在第一篇文章之中,我们知道了作用域链的查找规则即内层作用域一定可以访问到外层作用域中的变量对象的;在第二篇文章之中,我们知道当一个函数执行完成之后,它的执行上下文是一定会被销毁出栈的。那么现在请你思考一个问题,当函数的执行上下文被销毁时,我们还能够访问到它作用域中的变量吗?乍一看,你可能会觉得这个问题好奇怪,函数的执行上下文已经被销毁出栈了,我们还怎么拿到它内部的变量的呢。嘿嘿嘿,其实是可以的,今天我们就来聊一下其中的一种方法------闭包。

二. 辨析作用域链和执行上下文

在此之前,我们先来复习一下之前的内容。在之前的文章中,我们说到作用域链 相当一个由当前作用域和上层所有作用域所组成的链表,用于查找变量的值。作用域链的查找规则是由内向外的。执行上下文是代码执行时的运行环境,JS 引擎每执行一段代码就会创建一个执行上下文并压入执行栈。当代码执行完毕时,执行上下文会被销毁出栈

现在让我来忽悠一下你,来看下面这段代码

JS 复制代码
var a = 10;
function foo2() {
  console.log(a);
}

function foo1() {
  var a = 20;
  console.log(a);
  foo2();
}
foo1(); 

按照上一篇文章来分析的话,程序开始执行,首先会创建全局执行上下文,压入栈底,随着代码运行创建 foo1的执行上下文并压入栈,最后创建 foo2的执行上下文压入栈,如上图所示。那当执行到函数 foo2时,要 console.log(a),那么这个 a 是不是也是应该按照由内向外的原则往 foo1里面找呢?嘿嘿嘿,然后让我们来运行一下

嗯?怎么回事,难道不是输出 20 20 吗?你可能已经发现问题了,这是执行上下文呀,我们的作用域可不是这样的。被我忽悠到了吧,它的作用域链结构大概是这样的

现在你知道为什么输出为:20;10 了吗

注意!!!

当我们在分析函数内部变量的取值时,千万不要将作用域链与执行上下文混淆了,他们两个是有区别的

  1. 执行上下文 是动态的,它是在代码运行时确定的,随时可能改变
  2. 作用域 是静态的,作用域中的值一旦确定,永远都不会改变。函数可以不被调用,但是作用域中的值,在函数创建时就已经被写入了,并且存储在作用域链对象里面
  3. 函数的作用域 是由它被定义的位置决定的,而不是在调用时决定的

三. 闭包

OK,讲清楚了作用域链和执行上下文,现在我们可以来聊闭包了。那什么是闭包呢?上代码

JS 复制代码
function foo() {
  var a = 1;
  return function bar() {
    console.log(a);
  }
}
var baz = foo();
baz(); // 1

输出为:1,我们来看一下它的执行上下文和作用域链

按照作用域来看,函数 bar 可以读取到函数 foo 的 a,所以输出为1没错

按照执行上下文,当函数 foo 将函数 bar 返回出去后,foo 就已经执行完了,它的执行上下文会被销毁出栈。那么当函数 baz 执行时,foo 不是已经不存在了吗,它怎么能拿到 foo 里面的值并输出的。那他们两个不是矛盾了吗?是的,他们就是矛盾了。那么 JS 为了解决这个问题,就发明了闭包。由此我们可以得到闭包的定义。

1. 闭包的定义

定义在函数 A 内部的函数 B ,当其使用了外层函数 A 作用域中的变量 并被拿到函数 A 外部执行时 ,为了保证程序的正常执行,在 A 函数执行完毕后,会将函数 B 所需要的变量留在一个集合并存入调用栈,这个集合就是闭包。它包含了函数 B 本身以及它所捕获的外层函数作用域中的变量。

所以上述图可以画成这样

故函数 baz 可以拿到 foo 中的变量,输出为:1

2. 闭包的作用

  1. 可以访问到外部函数的作用域
  2. 封装私有化变量
  3. 解决全局污染的问题

3. 闭包的缺点

  1. 会造成内存泄漏

四. 总结

到这里,闭包就讲完啦,你弄明白了吗?回到最开始的问题,除了闭包你还能说出哪些方法可以在函数外部拿到函数内部的变量吗?把你的答案打在评论区吧

相关推荐
Jmyd01231 小时前
Web端3D营销展厅技术实现路径:从素材上云到线索回流的数据链路
前端·3d·性能优化·三维数字化
半个落月1 小时前
LangChain Agent 中间件实战(上):生命周期、状态、短路与工具包
javascript·langchain
砚凝霜1 小时前
【软考信息安全】第二十二章 Web服务器安全分析与增强——Apache与IIS
服务器·前端·安全
半个落月1 小时前
LangChain Agent 中间件实战(下):DeepAgents文件权限、长期记忆与对话摘要
javascript·langchain
u0111026753 小时前
JPG、PNG、WebP 怎么选?按透明度、体积和使用场景做判断
前端·javascript·vue.js·图像处理·ai作画
jerrywus4 小时前
让 AI 写完代码后交一份报告:我改造了 answer-me-with-html
前端·claude·cursor
派小心.4 小时前
小程序分享链路中来源参数的传递校验
大数据·前端·数据库·人工智能·小程序·数据分析
hhb_6184 小时前
一键生成数据看板,ECharts实战演示
前端·javascript·echarts
Java后端的Ai之路4 小时前
08_React组件API
前端·react.js·前端框架
小马不起床5 小时前
零基础玩转 FastAPI_09:前端基础工程构建
前端·状态模式·fastapi