搜索
首页web前端js教程js中闭包的概念

js中闭包的概念

Jun 19, 2020 am 09:11 AM
javascript闭包

闭包并不是 JavaScript 特有的,大部分高级语言都具有这一能力。

什么是闭包?

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment).

这段是 MDN 上对闭包的定义,理解为:一个函数及其周围封闭词法环境中的引用构成闭包。可能这句话还是不好理解,看看示例:

function createAction() {
    var message = "封闭环境内的变量";
    
    return function() {
        console.log(message);
    }
}

const showMessage = createAction();
showMessage();    // output: 封闭环境内的变量

这个示例是一个典型的闭包,有这么几点需要注意:

  1. showMessagecreateAction 执行后从中返回出来的一个函数
  2. createAction 内部是一个封闭的词法环境,message 作为该封装环境内的变量,在外面是绝不可能直接访问。
  3. showMessagecreateAction 外部执行,但执行时却访问到其内部定义的局部变量 message(成功输出)。这是因为 showMessage 引用的函数(createAction 内部的匿名函数),在定义时,绑定了其所处词法环境(createAction 内部)中的引用(message 等)。
  4. 绑定了内部语法环境的匿名函数被 return 带到了 createAction 封闭环境之外使用,这才能形成闭包。如果是在 createAction 内部调用,不算是闭包。

好了,我相信 1, 2, 4 都好理解,但是要理解最重要的第 3 点可能有点困难 —— 困难之处在于,这不是程序员能决定的,而是由语言特性决定的。所以不要认为是“你”创建了闭包,因为闭包是语言特性,你只是利用了这一特性

如果语言不支持闭包,类似上面的代码,在执行 showMessage 时,就会找不到 message 变量。我特别想去找一个例子,但是很不幸,我所知道的高级语言,只要能在函数/方法内定义函数的,似乎都支持闭包。

把局部定义的函数“带”出去

前面我们提到了可以通过 return 把局部定义的函数带出去,除此之外有没有别的办法?

函数在这里已经成为“货”,和其他货(变量)没有区别。只要有办法把变量带出去,那就有办法把函数带出去。比如,使用一个“容器”对象:

function encase(aCase) {
    const dog = "狗狗";
    const cat = "猫猫";
    aCase.show = function () {
        console.log(dog, cat);
    };
}

const myCase = {};
encase(myCase);
myCase.show();      // output: 猫猫 狗狗

是不是受到了启发,有没有联想到什么?

模块和闭包

对了,就是 exports 和 module.exports。在 CJS (CommonJS) 定义的模块中,就可以通过 exports.something 逐一带货,也可以通过 module.exports = ... 打包带货,但不管怎么样,exports 就是带货的那一个,只是它有可能是原来安排的 exports 也可能是被换成了自己人的 exports

ESM (ECMAScript Module) 中使用了 importexport 语法,也只不过是换种方法带货出去而已,和 return 带货差不多,区别只在于 return 只能带一个(除非打包),export 可以带一堆。

还要补充的是,不管是 CJS 还是 ESM,模块都是一个封装环境,其中定义的东西只要不带出去,外面是访问不到的。这和网页脚本默认的全局环境不同,要注意区别。

如果用代码来表示,大概是定义模块的时候以为是这样:

const var1 = "我是一个顶层变量吧";
function maybeATopFunction() { }

结果在运行环境中,它其实是这样的(注意:仅示意):

// module factory
function createModule_18abk2(exports, module) {
    const var1 = "我是一个顶层变量吧";
    function maybeATopFunction() { }
}

// ... 遥远的生产线上,有这样的示意代码
const module = { exports: {} };
const m18abk2 = createModule_18abk2(module) ?? module;

// 想明白 createModule_18abk2 为什么会有一个随机后缀没?

还是那个函数吗?

扯远了,拉回来。思考一个问题:理论上来说,函数是一个静态代码块,那么多次调用外层函数返回出来的闭包函数,是同一个吗?

试试:

function create() {
    function closure() { }
    return closure;
}

const a = create();
const b = create();

console.log(a === b);   // false

如果觉得意外,那把 closure() 换种方式定义看会不会好理解一点:

function create() {
    closure = function() { }
    return closure;
}

如果还不能理解,再看这个:

function create() {
    const a = function () { };
    const b = function () { };
    console.log(a === b);   // false
}

能理解了不:每一次 function 都定义了一个新的函数。函数是新的,名字不重要 —— 你能叫小明,别人也能叫小明不是。

所以,总结一下:


闭包是由一个函数以及其定义时所在封闭环境内的各种资源(引用)构成,拿到的每一个闭包都是独一无二的,因为构成闭包的环境资源不同(不同的局部环境,定义了不同的局部变量,传入了不同的参数等)。

闭包,这回搞明白了!


推荐教程:《JS教程

以上是js中闭包的概念的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:segmentfault。如有侵权,请联系admin@php.cn删除
JavaScript:探索网络语言的多功能性JavaScript:探索网络语言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是现代Web开发的核心语言,因其多样性和灵活性而广泛应用。1)前端开发:通过DOM操作和现代框架(如React、Vue.js、Angular)构建动态网页和单页面应用。2)服务器端开发:Node.js利用非阻塞I/O模型处理高并发和实时应用。3)移动和桌面应用开发:通过ReactNative和Electron实现跨平台开发,提高开发效率。

JavaScript的演变:当前的趋势和未来前景JavaScript的演变:当前的趋势和未来前景Apr 10, 2025 am 09:33 AM

JavaScript的最新趋势包括TypeScript的崛起、现代框架和库的流行以及WebAssembly的应用。未来前景涵盖更强大的类型系统、服务器端JavaScript的发展、人工智能和机器学习的扩展以及物联网和边缘计算的潜力。

神秘的JavaScript:它的作用以及为什么重要神秘的JavaScript:它的作用以及为什么重要Apr 09, 2025 am 12:07 AM

JavaScript是现代Web开发的基石,它的主要功能包括事件驱动编程、动态内容生成和异步编程。1)事件驱动编程允许网页根据用户操作动态变化。2)动态内容生成使得页面内容可以根据条件调整。3)异步编程确保用户界面不被阻塞。JavaScript广泛应用于网页交互、单页面应用和服务器端开发,极大地提升了用户体验和跨平台开发的灵活性。

Python还是JavaScript更好?Python还是JavaScript更好?Apr 06, 2025 am 12:14 AM

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。 1.Python以简洁语法和丰富库生态着称,适用于数据分析和Web开发。 2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。

如何安装JavaScript?如何安装JavaScript?Apr 05, 2025 am 12:16 AM

JavaScript不需要安装,因为它已内置于现代浏览器中。你只需文本编辑器和浏览器即可开始使用。1)在浏览器环境中,通过标签嵌入HTML文件中运行。2)在Node.js环境中,下载并安装Node.js后,通过命令行运行JavaScript文件。

在Quartz中如何在任务开始前发送通知?在Quartz中如何在任务开始前发送通知?Apr 04, 2025 pm 09:24 PM

如何在Quartz中提前发送任务通知在使用Quartz定时器进行任务调度时,任务的执行时间是由cron表达式设定的。现�...

在JavaScript中,如何在构造函数中获取原型链上函数的参数?在JavaScript中,如何在构造函数中获取原型链上函数的参数?Apr 04, 2025 pm 09:21 PM

在JavaScript中如何获取原型链上函数的参数在JavaScript编程中,理解和操作原型链上的函数参数是常见且重要的任�...

微信小程序webview中Vue.js动态style位移失效是什么原因?微信小程序webview中Vue.js动态style位移失效是什么原因?Apr 04, 2025 pm 09:18 PM

在微信小程序web-view中使用Vue.js动态style位移失效的原因分析在使用Vue.js...

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用