【JavaScript闭包】JavaScript何为闭包,浅谈闭包的形成和意义
创始人
2024-03-04 15:44:56
0次

谈到js,必然逃不了闭包。
闭包到底是啥呢?我查了不少资料,解释真的是各种各样,千奇百怪,令人困惑。
我们先来看看一下各种解释

  • 红宝石书:闭包指的是那些引用了另一个函数作用域中变量的函数。
  • mdn : 闭包(closure)是一个函数以及其捆绑的周边环境状态的引用的组合
  • 其它 : 闭包就是指有权访问另一个函数作用域中的变量的函数
    这可以说是我们最常见的几种说法。
    第一和第三种说法,我们把句子整合一下,就是说闭包是个函数

然后再来说说我们常看见的闭包

function func() {const a = 1;return () => a;
}
const oFunc = func();

我相信大多数人一开始见到的闭包都是这样
一个内部函数引用了外部函数作用域的变量,然后这个函数被保存函数外部。

作用域

首先说一句,闭包一定跟作用域有关。
作用域有块级作用域,函数作用域,全局作用域。
函数之所以能访问到外部作用域中的变量和函数,正是因为有作用域链的存在。

作用域是当前的执行上下文,值 和表达式在其中“可见”或可被访问。如果一个变量 或表达式不在当前的作用域中,那么它是不可用的。作用域也可以堆叠成层次结构,子作用域可以访问父作用域,反过来则不行。

一句话内层作用域能访问外层作用域的东西。

这跟一个东西有关。叫作用域链。

作用域链[[scope]]其实就是包含指针的列表,可以看作是一个数组,每个指针都指向一个变量对象。

这里的变量对象又牵扯到另一个东西叫做执行上下文。

执行上下文

执行上下文是动态的,当函数或程序执行时,会创建自己的执行上下文推入执行上下文栈中,执行上下文可以认为是代码的一个执行环境,所有代码都是在执行上下文环境中执行的。

JavaScript执行上下文有全局执行上下文,和函数执行上下文。

执行上下文有一个变量对象,全局执行上下文的变量对象叫做全局上下文对象,函数执行上下文的变量对象叫做活动对象。

当一个函数要执行时,会把它的执行上下文推入调用栈,调用栈始终执行栈顶的代码,当函数的代码执行完成后就会把函数的执行上下文弹出栈顶。因为js最开始是进入全局环境,所以调用栈的栈底是全局执行上下文。

变量对象在执行上下文中。

以下面的代码为例
我们来看看[[scope]]

function wrapper() {function inner() { }
}

inner执行时的作用域链
在这里插入图片描述
wrapper执行时的作用域链
在这里插入图片描述

从作用域链来看,外部函数的作用域链里没有内部函数的变量对象,自然访问不到内部函数的任何东西,这也是在情理之中。
上面wrapper执行时的作用域链也可以认为是inner定义时的作用域链。

前置知识已经了解。

那么什么是闭包呢?以下都是我的认为,不敢说百分百正确。

闭包

首先,闭包一定不是一个函数。我更喜欢说,它是内部函数访问其它函数作用域里变量或函数的一种现象。
首先说一下我在写这篇文章前一段时间对闭包的一个认识。

只要在函数内部用到了其它作用域的变量那么就会产生闭包。

这句话不能说他是错的,而且也是我认为最接近闭包的一个解释。
最具权威的就是mdn了。
我们直接上代码。

let g = 10;
function a() {let a1 = 10, a2 = 20, a3 = () => { }; // 外层函数作用域let yx = 10;{   // 块级作用域let block1 = 10;let block2 = 20(function (e) {g; // 用到了全局作用域里的变量a1; // 用到了a函数作用域的变量a2; // 用到了a函数作用域的变量a3(); // 用到了a函数作用域的函数block1; // 用到了块级作用域的变量block2; // 用到了块级作用域的变量console.dir(arguments.callee); // 打印函数本身的引用})(5);}// 函数并没有保存到外部 而是直接执行了
}
a();

控制台打印结果
在这里插入图片描述

我们看到一个很眼熟的东西Closure

闭包(closure)是一个函数以及其捆绑的周边环境状态的引用的组合

这不就是mdn上的一个解释吗?
我们看到它保存了内部函数引用到的外层函数作用域里的几个变量和函数,a1,a2,a3。
但它却没有包含yx。
很显然闭包只保存了用到的变量和函数,而且这些变量和函数所存在的作用域应该是函数作用域。
在打印结果中
块级作用域引用到的变量被保存在Block
全局作用域引用到的变量被保存在Script

其实这里我在想,Block和Script算不算是闭包的另一种表示。

闭包是什么呢?

mdn : 闭包(closure)是一个函数以及其捆绑的周边环境状态的引用的组合

闭包是其实就是将函数与这个函数用到的其它(函数)作用域里变量或函数进行捆绑的一种现象,因为他们捆绑在一起了,所以当这个函数还能访问到的情况下,与它捆绑在一起的变量和函数都不能被垃圾回收器回收,所以我们也经常说,闭包容易导致内存占用。

正常情况下产生的闭包,是不会有内存占用的危险,比如上面的代码,函数执行完后,其它地方根本不能访问到这个函数,所以函数会被垃圾回收器回收,与之形成闭包的变量和函数也将被释放。

上面函数我之所以打上括号,是因为我不太清楚是不是仅包括函数作用域。
但是既然mdn上的解释只是强调周边环境,那应该是包括了块级作用域和全局作用域。

好了我的看法大概就是这些。

有位网友说的很好,也很容易懂。我们来看一下。
在这里插入图片描述
其实他的解释跟我的解释差不多,只不过他解释的更通俗易懂。

闭包的意义

其实闭包的意义
我想说就是因为有闭包所以我们的函数才能在任何地方都能访问与它捆绑在一起的变量和函数。

然后就是闭包在我们开发中的意义
私有化变量这些大家应该都懂。我觉得没必要讲。

以上都是我的见解。

相关内容

热门资讯

前端-session、jwt 目录:   (1)session (2&#x...
linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
nodejs:本地安装nvm实... 一、背景-使用不同版本node的原因 vue3+ts、nuxt3版本,node...
JAVA集合知识整理 Java集合知识整理 HashMap相关 HashMap的底层数据结构:jdk1.8之...
无刷直流电机介绍及单片机控制实... 无刷直流电机介绍及单片机控制实例前言基本概念优势与劣势使用寿命基本结构使用单片机控制实例电子调速器&...
fwdiary(2) dp2 1.传纸条  AcWing 275. 传纸条 - AcWing 走两条路,走一条最大的...
常用的DOS命令 常用的DOS命令 DOS(Disk Operating System,磁...
<C++> 类和对象(下) 1.const成员函数将const修饰的“成员函数”称之为const成员函数,cons...