返回顶部
首页 > 资讯 > 前端开发 > JavaScript >一文剖析JavaScript中闭包的难点
  • 392
分享到

一文剖析JavaScript中闭包的难点

2024-04-02 19:04:59 392人浏览 薄情痞子
摘要

目录一、作用域基本介绍1. 全局作用域2. 函数作用域3. 块级作用域二、什么是闭包1. 闭包的基本概念2. 闭包产生的原因3. 闭包的表现形式三、如何解决循环输出问题1. 利用 I

一、作用域基本介绍

ES6之前只有全局作用域与函数作用域两种,ES6出现之后,新增了块级作用域。

1. 全局作用域

javascript中,全局变量是挂载在window对象下的变量,所以在网页中的任何位置你都可以使用并且访问到这个全局变量。

当我们定义很多全局变量的时候,会容易引起变量命名的冲突,所以在定义变量的时候应该注意作用域的问题:

var globalName = 'global'
function getName() {
  console.log(globalName) // global
  var name = 'inner'
  console.log(name) // inner
}
getName()
console.log(name) // 报错
console.log(globalName) // global
function setName() {
  vName = 'setName'
}
setName()
console.log(vName) // setName
console.log(windwo.vName) // setName

2. 函数作用域

在JavaScript中,函数定义的变量叫作函数变量,这个时候只能在函数内部才能访问到它,所以它的作用域也就是函数的内存,称为函数作用域。

当这个函数被执行完之后,这个局部变量也相应会被销毁。所以你会看到在getName函数外面的name是访问不到的:

function getName() {
  var name = 'inner'
  console.log(name) // inner
}
getName()
console.log(name) // 报错

3. 块级作用域

ES6新增了块级作用域,最直接的表现就是新增的let关键词,使用let关键词定义的变量只能在块级作用域中被访问,有"暂时性死区"的特定,也就是说这个变量在定义之前是不能被使用的。

if语句及for语句后面的{...}这里面所包括的,就是块级作用域:

console.log(a) // a is not defined
if (true) {
  let a = '123'
  console.log(a) // 123
}
console.log(a) // a is not defined

二、什么是闭包

红宝书:闭包是指有权访问另外一个函数作用域中的变量的函数 MDN:一个函数和对其周围状态的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。

1. 闭包的基本概念

闭包其实就是一个可以访问其他函数内部变量的函数。即一个定义在函数内部的函数,或者直接说闭包是个内嵌函数也可以。

因为通常情况下,函数内部变量是无法在外部访问的(即全局变量和局部变量的区别),因此使用闭包的作用,就具备实现了能在外部访问某个函数内部变量的功能,让这些内部变量的值始终可以保存在内存中。

function fun1() {
  var a = 1
  return function () {
    console.log(a)
  }
}
fun1()
var result = fun1()
result() // 1

2. 闭包产生的原因

当访问一个变量时,代码解释器会首先在当前的作用域查找,如果没找到,就去父级作用域去查找,直到找到该变量或者不存在父级作用域中,这样的链路就是作用域链。

var a = 1
function fun1() {
  var a = 2
  function fun2() {
    var a = 3
    console.log(a) // 3
  }
}
// fun1 函数的作用域指向全局作用域(window)和它自己本身;fun2 函数的作用域指向全局作用域(window)、fun1 和它本身;而作用域是从最底层向上找,直到找到全局作用域 window 为止,如果全局还没有的话就会报错

function fun1() {
  var a = 2
  function fun2() {
    console.log(a) // 2
  }
  return fun2
}
var result = fun1()
result()
// 那是不是只有返回函数才算是产生了闭包呢?其实也不是,回到闭包的本质,**我们只需要让父级作用域的引用存在即可**

var fun3
function fun1() {
  var a = 2
  fun3 = function () {
    console.log(a)
  }
}
fun1()
fun3()

闭包产生的本质:当前环境中存在指向父级作用域的引用。

3. 闭包的表现形式

返回一个函数,上面将原因的时候已经说过,这里就不在赘述了。

在定时器、事件监听、ajax请求、WEB Workers 或者任何异步中,只要使用了回调函数,实际上就是在使用闭包。

// 2.1定时器
setTimeout(function handler() {
  console.log('1')
}, 1000)
// 2.2事件监听
$('app').click(function () {
  console.log('Event Listener')
})

作为函数参数传递的形式,比如下面的例子:

// 3.作为函数参数传递的形式
var a = 1
function foo() {
  var a = 2
  function baz() {
    console.log(a)
  }
  bar(baz)
}
function bar(fn) {
  // 这就是闭包
  fn()
}
foo() // 输出2,而不是1

IIFE(立即执行函数),创建了闭包,保存了全局作用域(window)和当前函数的作用域,因此可以输出全局的变量,如下所示:

// 4.IIFE(立即执行函数)
var a = 2
(function IIFE() {
  console.log(a) // 输出2
})()

IIFE 这个函数会稍微有些特殊,算是一种自执行匿名函数,这个匿名函数拥有独立的作用域。这不仅可以避免了外界访问此 IIFE 中的变量,而且又不会污染全局作用域,我们经常能在高级的 JavaScript 编程中看见此类函数。

三、如何解决循环输出问题

for (var i = 1; i <= 5; i++) {
  setTimeout(function () {
    console.log(i)
  }, 0)
}
// 依次输出 5个6

setTimeout 为宏任务,由于 js 中单线程 eventLoop 机制,在主线程同步任务执行完后才去执行宏任务,因此循环结束后 setTimeout 中的回调才依次执行。

因为 setTimeout 函数也是一种闭包,往上找它的父级作用域就是 window,变量 i 为 window 上的全局变量,开始执行 setTimeout 之前变量 i 已经是 6 了,因此最后输出的连续都是 6。

1. 利用 IIFE

利用 IIFE,当每次 for 循环时,把此时的变量 i 传递到定时器中,然后执行:

for (var i = 1; i <= 5; i++) {
  (function (j) {
    setTimeout(function timer() {
      console.log(j)
    }, 0)
  })(i)
}

2. 使用 ES6 中的 let

let 让 JS 有了块级作用域,代码的作用域以块级为单位进行执行:

for(let i = 1; i <= 5; i++) {
  setTimeout(function() {
    console.log()
  },0)
}

3. 定时器传入第三个参数

setTimeout 作为经常使用的定时器,它是存在第三个参数的,日常工作中我们经常使用的一般是前两个,一个是回调函数,另外一个是时间,而第三个参数用得比较少:

for(var i=1;i<=5;i++) {
  setTimeout(function(j) {
    console.log(j)
  },0,i)
}

第三个参数的传递,改变了 setTimeout 的执行逻辑,从而实现我们想要的结果,这也是一种解决循环输出问题的途径。

到此这篇关于一文剖析JavaScript中闭包的难点的文章就介绍到这了,更多相关JavaScript闭包内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 一文剖析JavaScript中闭包的难点

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

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

猜你喜欢
  • 一文剖析JavaScript中闭包的难点
    目录一、作用域基本介绍1. 全局作用域2. 函数作用域3. 块级作用域二、什么是闭包1. 闭包的基本概念2. 闭包产生的原因3. 闭包的表现形式三、如何解决循环输出问题1. 利用 I...
    99+
    2024-04-02
  • JavaScript闭包中难点深入分析
    目录初识闭包什么是闭包如何产生闭包产生闭包条件闭包的作用闭包的生命周期闭包的应用闭包的缺点及解决方法闭包案例初识闭包 闭包可谓是JS的一大难点也是面试中常见的问题之一,今天开始梳理一...
    99+
    2022-11-13
    JavaScript闭包 JS闭包
  • 闭包的谜题:剖析 JavaScript 闭包中的常见问题
    闭包通过在内部函数中引用外部变量来捕获变量。当外部函数返回时,内部函数仍然可以访问这些外部变量,即使外部函数本身已被销毁。 问题 2:闭包的陷阱是什么? 内存泄漏:如果闭包持有对外部变量的引用,而外部变量又引用了一些大型对象,则即使外部函...
    99+
    2024-03-14
    闭包
  • 一文搞懂JavaScript中最难理解概念之一的闭包
    目录一、闭包的概念二、怎么实现闭包三、闭包的用途1.封装私有变量2. 做缓存3. 模块化编程(实现共有变量)四、闭包的缺点五、最后的话一、闭包的概念 当通过调用外部函数返回的内部函数...
    99+
    2023-05-14
    JavaScript闭包实现 JavaScript闭包应用 JavaScript闭包
  • 一文详解JavaScript中的闭包
    JavaScript 闭包是一种重要的概念,在 JavaScript 编程中被广泛使用。尽管它可能会让初学者感到困惑,但它是理解 JavaScript 语言核心的关键概念之一。本文将深入探讨 JavaScript 闭包,让你了解它是如何工作...
    99+
    2023-05-14
    闭包 前端 JavaScript
  • 一文浅析Golang中的闭包
    1、什么是闭包?在真正讲述闭包之前,我们先铺垫一点知识点:函数式编程函数作用域作用域的继承关系【相关推荐:Go视频教程】1.1 前提知识铺垫1.2.1 函数式编程函数式编程是一种编程范式,看待问题的一种方式,每一个函数都是为了用小函数组织成...
    99+
    2023-05-14
    闭包 Go 后端
  • 一文了解JavaScript闭包函数
    目录变量作用域闭包的概念闭包的用途闭包的缺点最后总结一下闭包的好处与坏处总结变量作用域 要理解JavaScript闭包,就要先理解JavaScript的变量作用域。 变量的作用域有...
    99+
    2024-04-02
  • Javascript中的闭包知识点讲解
    本篇内容介绍了“Javascript中的闭包知识点讲解”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. ...
    99+
    2024-04-02
  • 破解闭包难题:回答有关 JavaScript 闭包的关键问题
    闭包是指 JavaScript 中一种特殊类型的函数,它可以访问其所在作用域之外的变量。这允许我们创建保存状态的函数,即使其调用程序已经完成执行。 关键问题 1. 闭包如何工作? 闭包通过创建内部函数来实现,该内部函数可以访问其外部函数的...
    99+
    2024-03-14
    闭包
  • JavaScript中的闭包
    一.什么是闭包 1.闭包的定义 闭包并不是JS特有的,因此可以从两个角度定义闭包。 1)计算机科学中 闭包又称为词法闭包(在进行词法分析的时候这个闭包就确定了),或者是函数闭包。是在支持头等函数的编程语言中(意思是函数作为一等公民的编程语言...
    99+
    2023-08-18
    javascript 前端 java
  • JavaScript闭包的示例分析
    小编给大家分享一下JavaScript闭包的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!闭包是JavaScript中的...
    99+
    2024-04-02
  • 怎样解析javascript的闭包
    今天就跟大家聊聊有关怎样解析javascript的闭包,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。什么是闭包:闭包是一个存在内部函数的引用关系。该引用指向的是外部函数的局部变量对象...
    99+
    2023-06-29
  • Javascript中return与闭包的示例分析
    这篇文章给大家分享的是有关Javascript中return与闭包的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、return的使用案例一:var a=1;...
    99+
    2024-04-02
  • 一文详解JavaScript闭包典型应用
    目录1.应用1.1 模拟私有变量1.2 柯里化1.3 偏函数1.4 防抖1.5 节流2.性能问题2.1 内存泄漏2.2 常见的内存泄漏3.闭包与循环体3.1 这段代码输出啥3.2 改...
    99+
    2024-04-02
  • 一文了解你不知道的JavaScript闭包篇
    目录前言理解闭包升级版闭包循环和闭包模块小结前言 JavaScript语言中有一个非常重要又难以掌握,近似神话的概念-闭包。对于有一点JavaScript使用经验但从未真正理解闭包概...
    99+
    2022-11-13
    JavaScript 闭包
  • 分析css与javascript的重难知识点
    这篇文章主要讲解了“分析css与javascript的重难知识点”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“分析css与ja...
    99+
    2024-04-02
  • 剖析 Python Django 中的数据库连接难题
    常见连接难题 以下是 Django 中常见的数据库连接难题: 超出最大连接数:当应用程序打开的连接超出数据库允许的最大连接数时,会出现此错误。 无法建立连接:应用程序无法与数据库建立连接,通常是由于配置错误或服务器不可用。 数据库暂时...
    99+
    2024-02-15
    Django 数据库 连接 故障排除 优化
  • JavaScript中闭包的使用
    本篇内容介绍了“JavaScript中闭包的使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!通过深入了解...
    99+
    2024-04-02
  • JavaScript MVC 架构的弱点剖析:知己知彼
    模型-视图-控制器 (MVC) 架构是 JavaScript 开发中广泛采用的设计模式,它通过分离关注点来提高应用程序的组织性、可测试性和可维护性。然而,就像任何架构模式一样,MVC 架构也存在一些固有的弱点,需要开发人员在实施时加以考...
    99+
    2024-03-02
    JavaScript、MVC 架构、弱点、可维护性、性能
  • javascript中变量提升和闭包的示例分析
    这篇文章主要介绍了javascript中变量提升和闭包的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。我们先来看一个题目:<s...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作