js中闭包的概念

闭包并不是 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: 封闭环境内的变量

登录后复制

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

showMessage 是 createAction 执行后从中返回出来的一个函数。createAction 内部是一个封闭的词法环境,message 作为该封装环境内的变量,在外面是绝不可能直接访问。showMessage 在 createAction 外部执行,但执行时却访问到其内部定义的局部变量 message(成功输出)。这是因为 showMessage 引用的函数(createAction 内部的匿名函数),在定义时,绑定了其所处词法环境(createAction 内部)中的引用(message 等)。绑定了内部语法环境的匿名函数被 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) 中使用了 import 和 export 语法,也只不过是换种方法带货出去而已,和 return 带货差不多,区别只在于 return 只能带一个(除非打包),export 可以带一堆。

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

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

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

登录后复制

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

// module factoryfunction 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中闭包的概念的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2727689.html

(0)
上一篇 2025年3月7日 23:47:54
下一篇 2025年3月7日 23:48:04

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • Object.fromEntries和Object.entries的使用

    object.entries() 转换一个object为array。但是,如果你想做相反的事情怎么办?不用再想了! 使用 object.fromentries() 来把array转换为object。 const keyValuePair =…

    2025年3月7日
    200
  • 前端的基础知识巩固

    分类巩固一下前端的基础知识 很久没有回头看看html和js的一些基础知识了,周末闲来无事的时候看到了一篇关于面试题的文章,突然发现很多都忘记了,好的,那就趁热打铁,撸一波基础知识吧。 关于HTML html是超文本标记语言(Hyper Te…

    编程技术 2025年3月7日
    200
  • JavaScript document.write() 用法

    document.write() 用法 在JavaScript中document.write()函数可以向文档写入HTML表达式或JavaScript代码,用法“document.write(exp1,exp2,exp3,….)…

    2025年3月7日
    200
  • 用JavaScript检测出当前浏览器是否是无头浏览器

    什么是无头浏览器(headless browser)? 无头浏览器是指可以在图形界面情况下运行的浏览器。我可以通过编程来控制无头浏览器自动执行各种任务,比如做测试,给网页截屏等。 为什么叫“无头”浏览器? “无头”这个词来源于最初的“无头计…

    2025年3月7日
    200
  • 一起学习Javascript网页截屏的方法

    之前我曾写过如何将canvas图形转换成图片和下载canvas图像的方法,这些都是在为这个插件做技术准备。 技术路线很清晰,将网页的某个区域的内容生成图像,保持到canvas里,然后将canvas内容转换成图片,保存到本地,最后上传到微博。…

    2025年3月7日
    200
  • 分享 10 个提高 JavaScript 技能的测验问答

    刷题是我们提高自己技术的一种好方法。下面的问题很有挑战性和“指导性”。如果你知道该怎样回答,那意味着自己的水平很好,但是如果你发现自己答错了,并能够搞清楚为什么错,我认为那会更好! 推荐学习:JavaScript视频教程  、 js教程(图…

    2025年3月7日
    200
  • 原生JS使用transform实现banner的无限滚动效果

    功能 默认情况无限循环向右移动点击数字切换到对应图片点击左右切换可切换图片 原理 首先说下原理。 在布局上所有的图片都是重叠的,即只要保证Y方向对齐即可,当前可见的图z-index层级最高。每隔3s中更换一张图片,使用setTimeout定…

    2025年3月7日 编程技术
    200
  • Canvas实现动态粒子连线效果(附代码)

    本篇文章给大家通过示例来介绍一下js+canvas制作动画,实现动态粒子连线效果的方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。 JS+Canvas制作动画,实现动态粒子连线效果 效果图如下 思路如下: 绘制随机区域…

    2025年3月7日
    200
  • 带你了解ES6的Set,WeakSet,Map和WeakMap

    之前在学习 es6 的时候,看到 set 和 map,不知道其应用场景有哪些,只觉得很多时候会用在数组去重和数据存储,后来慢慢才领悟到 set 是一种叫做集合的数据结构,map 是一种叫做字典的数据结构。 本文在gitthub做了收录:gi…

    编程技术 2025年3月7日
    200
  • 8个问题测试你的JavaScript基础

    JavaScript 是一种有趣的语言,我们都喜欢它,因为它的性质。浏览器是JavaScript的主要运行的地方,两者在我们的服务中协同工作。JS有一些概念,人们往往会对它掉以轻心,有时可能会忽略不计。原型、闭包和事件循环等概念仍然是大多数…

    编程技术 2025年3月7日
    200

发表回复

登录后才能评论