深入理解JavaScript闭包

【浙大翁恺】C语言习题 /* 02-0. 整数四则运算(10) 本题要求编写程序,计算2个正整数的和、差、积、商并输出。 题目保证输入和输出全部整型范围内。 输入格式: 输入在一行中给出2个正整数A和B。 输出格式: 在4行中按照格式“A 运算符 B = 结果”顺序输出和、差、积、商。 输入样例: 3 2 输出样例: 3 + 2 = 5 3 - 2 = 1 3 * 2 = 6 3 / 2 =. 阅读详情

定义

闭包的定义:

闭包是指那些能访问自由变量的函数。

自由变量:

自由变量是指在函数中使用的,但既不是函数参数也不是函数的局部变量的变量。

所以我们可以理解为闭包是由 函数 + 自由变量 组成的。

换句话说,闭包就是函数和被创建的函数中的作用域对象的组合。

所以在理论上所有JavaScript函数都是闭包。

ECMAScript中,闭包指的是:

  1. 从理论角度:所有的函数。因为它们都在创建的时候就将上层上下文的数据保存起来了。哪怕是简单的全局变量也是如此,因为函数中访问全局变量就相当于是在访问自由变量,这个时候使用最外层的作用域。
  2. 从实践角度:以下函数才算是闭包:
    • 即使创建它的上下文已经销毁,它仍然存在(比如,内部函数从父函数中返回)
    • 在代码中引用了自由变量

回顾

在上一篇《深入理解JavaScript执行上下文》文章中使用过一个例子:

var scope = 'global scope'
function checkscope(){
    var scope = 'local scope'
    function f(){
        return scope
    }
    return f
}
checkscope()()

这段代码的执行在上一篇文章有具体的分析,在这里我们可能会有一个疑问(分析可参考上一篇文章):

在f函数的执行上下文入栈之前,checkscope函数已经出栈,那么为什么还能读取scope的值呢?

其实我们看分析可以知道在f函数执行上下文中维护了一个作用域链

fContext = {
    Scope: [AO, checkscopeContext.AO, globalContext.VO]
}

就是因为这条作用域链的存在,才使得f函数在checkscope函数执行上下文销毁后仍能读取checkscopeContext.AO中的值,因为f函数与checkscopeContext.AO存在引用关系,所以即使checkscope函数执行上下文已经销毁,但是checkscopeContext.AO仍活在内存中,f函数仍能通过作用域链找到scope的值。

问题

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

答案都是5,我们的预期是顺序输出0到4,和我们的预期不同。我们分析一下原因:

在执行定时器内fn函数之前,全局上下文的VO为:

globalContext = {
    VO: {
        i: 5
    }
}

当fn函数执行时,fn函数的作用域链为:

fnContext = {
    Scope: [AO, globalContext.VO]
}

在fnContext的AO中并没有i的值,所以会从globalContext.VO查找,而这时在globalContext.VO中i的值为5,所以最终打印出来的结果为5.

很多人会使用下面这种方法:

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

我们发现输出的结果符合我们的预期,但是输出结果时并没有1s的延时。

这是因为在定时器内的第一个()是一个分组操作符,里面的函数fn为一个函数表达式而非函数声明,所以定时器内第一个参数相当于执行fn(i),并不会延时执行,这也就是我们常说的立即执行函数。

接下来我们继续使用闭包来解决这个问题:

for (var i = 0 ; i < 5 ; i++){
    setTimeout((function(i) {
        return function fn() {
            console.log(i)         
        }
    })(i), 1000)
}

我们在fn函数外层加一个立即执行函数并将i的值传入,这样就能够得到我们想要的答案,我们对比之前的fn函数执行时的作用域链:

fnContext = {
    Scope: [AO, 匿名Context.AO, globalContext.VO]
}

在闭包中fn函数的作用域链中多了一个匿名函数的AO,在这个AO中便存有匿名函数执行时保存在AO中的i值。这样在匿名函数的AO中找到i的值,也就不会再去找globalContext.VO中i值。

179、运动控制中的行业标准:机器人安全标准ISO 10218 今天这篇笔记,就把我踩过的坑和标准里的硬骨头掰开揉碎讲清楚。 阅读详情

相关推荐

PADS Logic VX2.5元件绘制全流程:从零开始创建自定义元件库

本文详细介绍了在PADS Logic VX2.5中从零开始创建自定义元件库的全流程。内容包括理解PADS独特的四库分立结构、绘制原理图符号(CAE封装)、关联PCB封装、创建元件类型以及最终的调用验证。掌握元件绘制技能能从根本上提升设计效率、确保设计规范统一,并从源头杜绝原理图与PCB之间的关联错误,是硬件工程师必备的核心能力。

oo7890的博客 444

js循环输出helloworld

代码如下: html> html lang="en"> head> meta charset="UTF-8"> title>循环输出helloworldtitle> script type="text/javascript"> document.write('使用javascript循环打印helloworld') for(var i=

wo7024389的博客 4328

用户存续期价值评估CLV(二) BG/NBD Model python模拟

BG/NBD Model …继续 想象每一个客户有两个硬币,一个“Buy Coin"控制客户购买的概率;一个"Die Coin"控制客户流失、不再购买的概率。 前面假设了客户的交易次数服从泊松过程: 在一年中的每个月,客户都以抛硬币的方式来决定是否购买。我们所观察到的购买次数取决与泊松分布的参数 ????。 %matplotlib inline import numpy as np impor...

weixin_43171270的博客 3428

javascript深入理解js闭包

javascript深入理解js闭包 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。

记事本 3746

S7-1500与WinCC GroupDisplay组显示的高效配置指南

本文详细介绍了S7-1500 PLC与WinCC GroupDisplay组显示功能的高效配置方法,涵盖报警状态配置、WinCC端组显示控件设置及常见问题排查。通过实战案例和优化建议,帮助工程师快速掌握工业自动化项目中报警信息可视化的关键技术,提升生产线监控效率。

weixin_29292535的博客 441

Vertx之Grpc消息发送

介绍 Vert.x gRPC 模块,它将 Google gRPC 的编程风格与 Vert.x 风格保持一致. gRPC 是一个高性能、开源、通用的RPC框架,是一种进程间通讯技术,由Google推出,基于HTTP2协议标准设计开发,默认采用Protocol Buffers数据序列化协议,支持多种开发语言。gRPC提供了一种简单的方法来精确的定义服务,并且为客户端和服务端自动生成可靠的功能库。 在gRPC客户端可以直接调用不同服务器上的远程程序,使用姿势看起来就像调用本地程序一样,轻松的实现远端服务的连接、

Lance 1189

js 闭包传参_javascript深入理解js闭包

一、变量的作用域要理解闭包,首先必须理解Javascript特殊的变量作用域。变量的作用域无非就是两种:全局变量和局部变量。Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。var n=999;function f1(){alert(n);}f1(); // 999另一方面,在函数外部自然无法读取函数内的局部变量。function f1(){var n=999;}alert(...

weixin_28760959的博客 422

IROS 2025机器人技术解析:从诡异设计到硬核应用

机器人技术正从传统的结构化环境应用,迈向复杂非结构化场景的深度交互。其核心原理在于通过仿生设计、多模态感知与智能控制算法,赋予机器人类似生物的适应性与交互能力。这一技术演进的价值在于突破传统机器人在极端环境、精密操作和自然交互中的瓶颈。例如,结合深度强化学习的全身动力学控制,使机器人能在废墟、管道等复杂地形中自主导航;而软体机器人技术则通过材料变形实现安全、柔顺的抓取操作。这些技术最终服务于极端环境巡检、精密装配和高端陪护等刚性应用场景,推动机器人从功能实现迈向与环境、人进行深度、智能交互的新阶段。

weixin_34006468的博客 453
上一篇: 深入理解JavaScript执行上下文
Anpoly
博客等级 码龄10年 10粉丝 10原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值