返回顶部
首页 > 资讯 > 精选 >JavaScript闭包是什么及怎么用
  • 381
分享到

JavaScript闭包是什么及怎么用

2023-07-04 13:07:53 381人浏览 泡泡鱼
摘要

这篇“javascript闭包是什么及怎么用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“JavaScript闭包是什么及怎

这篇“javascript闭包是什么及怎么用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“JavaScript闭包是什么及怎么用”文章吧。

闭包是什么?

对于一个知识点来说,我一直认为不论是从什么方面入手,都需要彻底弄懂三个问题,才算真正了解这个知识点,然后具体再去实践中练习,才能称得上掌握。这三个问题就是:

  • 是什么?

  • 为什么要设计?

  • 能用在哪?

首先先回答闭包是什么这个问题。应该大多数人也看过很多与之相关的文章,很多人也给出了自己的解释,所以我也先给出自己理解的解释,那就是:先有两个前置的概念:

  • 闭包是在词法分析时就已经被确定的, 所以它会与词法作用域有关。

  • 闭包存在的前置条件是需要支持函数作为一等公民的编程语言,所以它会与函数有关。

所以最终的结论就是:

  • 闭包首先是一个结构体,这个结构体的组成部分为  一个函数 + 该函数所处的词法作用域

  • 也就是闭包是由一个函数并且该函数能够记住声明自己的词法作用域所产生的结构体

  • 在内存中理解就是, 当一个函数被调用时,它所产生的函数执行上下文里的作用域链保存有其父词法作用域,所以父变量对象由于存在被引用而不会销毁,驻留在内存中供其使用。这样的情况就称为闭包。

为什么要设计出闭包?

对于为什么设计这点,仅以我自己粗浅的理解就是由于JavaScript是异步单线程的语言。对于异步编程来说,最大的问题就是当你编写了函数,而等到它真正调用的时机可能是之后任意的时间节点。

这对于内存管理来说是一个很大的问题,正常同步执行的代码,函数声明时和被调用时所需要的数据都还存留在内存中,可以无障碍的获取。而异步的代码,往往声明该函数的上下文可能已经销毁,等到在调用它时,如果内存中已经把它所需要的一些外部数据给清理了,这就是个很大的问题。

所以JavaScript解决的方案就是让函数能够记得自己之前所能获取数据的范围,统统都保存在内存里,只要该函数没有被内存回收,它自身以及所能记住的范围都不会被销毁

这里的所能记住的范围就是指词法作用域,就是由于它是静态的,所以才需要记住。

这又是JavaScript设计作用域为静态的导致的。 如果是动态作用域,函数被调用时只需要被调用时的那个环境,就不需要存在记住自身作用域的事了。

所以总结一下就是:

  • 闭包是为了解决词法作用域引发的问题内存不好管理异步编程里数据获取所产生的。

经典题

由于有非常多的文章都从下面这个非常经典的面试题入手,但似乎都没有人真正从最底层讲解过,所以我就打算将整个过程梳理一遍,来明白这其中的差异性。

for (var i = 0; i < 3; i++) {  setTimeout(function cb() {    console.log(i);  }, 1000);}

基本所有有基础的人一眼就能看出输出的是三个3。

然后让修改成按顺序输出,通常只需要修改var成let:

for (let i = 0; i < 3; i++) {  setTimeout(function cb() {    console.log(i);  }, 1000);}

这样就成了输出为0,1,2.并且是同时间输出,而不是每间隔一秒输出一次。

那么问题来了,为什么?

这里可以先不看下面,先写写自己的解释,看看是否跟我写的一样。

1. 先来探讨变量i是var的情况。

当代码开始执行时,此时执行上下文栈和内存里的情况是这样:其中全局对象里的变量i和全局执行上下文里变量环境里的变量i是同一个变量。

JavaScript闭包是什么及怎么用

然后开始进行循环, 当 i = 0时,第一个定时器被丢入宏任务队列,关于宏任务相关的内容属于事件循环范畴,暂时只需要理解setTimeout会被丢入队列里,等之后执行。此时在堆内存中会创建它的回调函数cb,并且函数创建时会创建[[scope]],在实际ECMA的规则中,[[scope]]会指向该函数的父作用域,也就是当前的全局对象(作用域是概念上的东西,实际体现在内存中就是保存数据的一种结构,可能是对象也可能是其他)。但是在V8引擎的实现中,其实并不会指向全局对象,而是去分析该函数使用了父作用域中的哪些变量,将这些变量存储到Closure中,然后由scope指向。每个函数都有且只有一个Closure对象。

JavaScript闭包是什么及怎么用


这里先插入一下关于Closure对象可以在Chrome中哪看到的情况:可以看到,创建bar函数时,它只有引用了父作用域的name变量,所以在闭包对象中只会存储变量name, 而不会存在变量age。JavaScript闭包是什么及怎么用


同理之后的 i = 1, 和 i = 2 都是一样的,最终结果会变成:

JavaScript闭包是什么及怎么用

最终因为 i++导致 i = 3, 循环结束,全局代码执行完毕。此时的结果为:

然后开始进入定时器回调函数执行的过程,开始执行第一个定时器里的回调函数,压入了执行上下文栈中,执行输出i, 但是在词法环境和变量环境中找不到这个变量i,所以去自身[[scope]]向上寻找,在Closure对象中找到了 i 等于3,输出结果3。

JavaScript闭包是什么及怎么用

同理对于后面两个定时器也是一样的流程,并且实际上定时器开启的时间都是在循环中就立即执行的,导致实际上三个函数的定时1秒时间是一致的,最终输出的结果是几乎同时输出3个3。而不是每间隔1秒后输出3, 当然这是定时器相关的知识了。

2. 然后探讨通过var修改成let之后实际上变了什么

同样是刚创建时,所展示的情况为:

JavaScript闭包是什么及怎么用

之后进入循环体,当i = 0时:

JavaScript闭包是什么及怎么用

之后进入 i = 1时的情况:

JavaScript闭包是什么及怎么用

最后进入到 i = 2的情况,与 i = 1基本类似:

JavaScript闭包是什么及怎么用

最终 i++,变成i值为3,循环结束。开启定时器工作:

JavaScript闭包是什么及怎么用

当执行第一个定时器的回调函数时,创建了函数执行上下文,此时执行输出语句i时,会先从自己的词法环境里寻找变量i的值,也就是在 record环境记录里搜索,但是不存在。因而通过自己外部环境引用outer找到原先创建的块级作用域里 i = 0的情况, 输出了i值为0的结果。

对于之后的定时器也都是一样的情况,原先的块级作用域由于被回调函数所引用到了,因而就产生了闭包的情况,不会在内存中被销毁,而是一直留着。

等到它们都执行完毕后,最终内存回收会将之全部都销毁。

其实以上画的图并不是很严谨,与实际在内存中的表现肯定是有差异的,但是对于理解闭包在内存里的情况还是不影响的。

闭包能用在哪?

首先需要先明确一点,那就是在JavaScript中,只要创建了函数,其实就产生了闭包。这是广义上的闭包,因为在全局作用域下声明的函数,也会记着全局作用域。而不是只有在函数内部声明的函数才叫做闭包。

通常意义上所讨论的闭包,是使用了闭包的特性

1. 函数作为返回值

let a = 1function outer() {  let a = 2  function inside() {    a += 1    console.log(a)  }  return inside}const foo = outer()foo()

此处outer函数调用完时,返回了一个inside函数,在执行上下文栈中表示的既是outer函数执行上下文被销毁,但有一个返回值是一个函数。 该函数在内存中创建了一个空间,其[[scope]]指向着outer函数的作用域。因而outer函数的环境不会被销毁。

当foo函数开始调用时,调用的就是inside函数,所以它在执行时,先询问自身作用域是否存在变量a, 不存在则向上询问自己的父作用域outer,存在变量a且值为2,最终输出3。

2. 函数作为参数

var name = 'xavier'function foo() {  var name = 'parker'  function bar() {    console.log(name)  } console.log(name)  return bar}function baz(fn) {  var name = 'coin'  fn()}baz(foo())baz(foo)

对于第一个baz函数调用,输出的结果为两个'parker'。 对于第二个baz函数的调用,输出为一个'parker'。

具体的理解其实跟上面一致,只要函数被其他函数调用,都会存在闭包。

3. 私有属性

闭包可以实现对于一些属性的隐藏,外部只能获取到属性,但是无法对属性进行操作。

function foo(name) {  let _name = name  return {    get: function() {      return _name    }  }}let obj = foo('xavier')obj.get()

4. 高阶函数,科里化,节流防抖等

对于一些需要存在状态的函数,都是使用到了闭包的特性。

// 节流function throttle(fn, timeout) {  let timer = null  return function (...arg) {    if(timer) return    timer = setTimeout(() => {    fn.apply(this, arg)    timer = null    }, timeout)  }}// 防抖function debounce(fn, timeout){  let timer = null  return function(...arg){    clearTimeout(timer)    timer = setTimeout(() => {      fn.apply(this, arg)    }, timeout)  }}

5. 模块化

在没有模块之前,对于不同地方声明的变量,可能会产生冲突。而闭包能够创造出一个封闭的私有空间,为模块化提供了可能性。 可以使用IIFE+闭包实现模块。

var moduleA = (function (global, doc) {  var methodA = function() {};  var dataA = {};  return {    methodA: methodA,    dataA: dataA  };})(this, document);

以上就是关于“JavaScript闭包是什么及怎么用”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网精选频道。

--结束END--

本文标题: JavaScript闭包是什么及怎么用

本文链接: https://lsjlt.com/news/345393.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • JavaScript闭包是什么及怎么用
    这篇“JavaScript闭包是什么及怎么用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“JavaScript闭包是什么及怎...
    99+
    2023-07-04
  • JavaScript闭包是什么
    这篇文章给大家分享的是有关JavaScript闭包是什么的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。概论在讨论ECMAScript闭包之前,先来介绍下函数式编程(与ECMA-2...
    99+
    2024-04-02
  • 什么是JavaScript闭包
    本篇内容主要讲解“什么是JavaScript闭包”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“什么是JavaScript闭包”吧!什么是闭包简言之,闭包是由函数...
    99+
    2024-04-02
  • python函数及闭包是什么及怎么用
    本篇内容主要讲解“python函数及闭包是什么及怎么用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“python函数及闭包是什么及怎么用”吧!函数对象函数对象指...
    99+
    2024-04-02
  • JavaScript中什么是闭包
    这篇文章给大家介绍JavaScript中什么是闭包,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。 一 、词法定义域 LexicalClosure闭包是编程语言Lexical ...
    99+
    2024-04-02
  • Javascript闭包的作用是什么
    本篇内容主要讲解“Javascript闭包的作用是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Javascript闭包的作用是什么”吧!对于初学者来说,理...
    99+
    2024-04-02
  • JavaScript闭包是什么意思
    本篇内容介绍了“JavaScript闭包是什么意思”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!闭包是纯函数式编程语言的传统特性之一。通过将...
    99+
    2023-06-20
  • JavaScript中闭包的概念、原理及作用是什么
    本篇内容主要讲解“JavaScript中闭包的概念、原理及作用是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JavaScript中闭包的概念、原理及作用是...
    99+
    2024-04-02
  • javascript闭包有什么用
    这篇文章给大家分享的是有关javascript闭包有什么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。用处说明可以在函数外读取函数内部的变量,这些变量的值始终保持在内存中。闭包会将函数中的变量保存在存储器中,增...
    99+
    2023-06-20
  • Javascript闭包的特性是什么
    本篇内容介绍了“Javascript闭包的特性是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Java...
    99+
    2024-04-02
  • javascript中什么指的是闭包
    这篇文章主要为大家展示了“javascript中什么指的是闭包”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“javascript中什么指的是闭包”这篇文章吧。 ...
    99+
    2024-04-02
  • javascript的闭包是什么意思
    这篇文章将为大家详细讲解有关javascript的闭包是什么意思,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。 在javascript中,当两...
    99+
    2024-04-02
  • JavaScript中闭包有什么用
    这篇文章主要介绍JavaScript中闭包有什么用,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!1. 什么是闭包闭包:函数本身和该函数声明时所处的环境状态的组合。也就是说函数不在其定义的环境中被调用,也能访问定义时所...
    99+
    2023-06-25
  • JavaScript中闭包怎么用
    这篇文章将为大家详细讲解有关JavaScript中闭包怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。闭包真的是学过一遍又一遍,Js博大精深,每次学习都感觉有新的收获...
    99+
    2024-04-02
  • 在JavaScript函数中什么是闭包
    本篇内容介绍了“在JavaScript函数中什么是闭包”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!匿名函...
    99+
    2024-04-02
  • PHP闭包及Clourse类的作用是什么
    今天小编给大家分享一下PHP闭包及Clourse类的作用是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。PHP Clou...
    99+
    2023-06-29
  • golang闭包的概念及作用是什么
    闭包是指一个函数(匿名函数或者lambda函数)以及其相关的引用环境组合而成的实体。在Go语言中,闭包是一种特殊的匿名函数,它可以访...
    99+
    2024-02-29
    golang
  • JavaScript闭包哟哪些用途及怎么实现
    这篇文章主要介绍了JavaScript闭包哟哪些用途及怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇JavaScript闭包哟哪些用途及怎么实现文章都会有所收获,下面我们一起来看看吧。一、闭包的概念当通...
    99+
    2023-07-05
  • Javascript中的闭包有什么用
    这篇文章给大家介绍Javascript中的闭包有什么用,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。var array = []; array.lengt...
    99+
    2024-04-02
  • javascript中闭包有什么作用
    本篇内容介绍了“javascript中闭包有什么作用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!什么是闭...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作