尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
闭包之循环中捕获正确的值
先来看下面这几段 JavaScript 代码它们执行后分别会输出什么其中哪些能正常输出 0、1、2// 1、var 陷阱 for (var i 0; i 3; i) { setTimeout(() { console.log(i); }, 100); } // 2、 IIFE 闭包 for (var i 0; i 3; i) { (function(index) { setTimeout(() { console.log(index); }, 100); })(i); } // 3、 let 块级作用域 for (let i 0; i 3; i) { setTimeout(() { console.log(i); }, 100); } // 4、const 传统 for for (const i 0; i 3; i) { setTimeout(() { console.log(i); }, 100); } // 5、const for...of for (const i of [0, 1, 2]) { setTimeout(() { console.log(i); }, 100); }答案↓只有第 2、3、5 段能正常输出 0、1、2你答对了吗第 1 段执行后输出 3、3、3第 4 段则直接语法报错只输出 0。为什么会这样呢从零到精通~~来理解吧一、先看以下代码var i; for (i 0; i 3; i) { console.log(i); // ← 当场打印 } // 输出0, 1, 2 ✅ // ----------------------------------------------------------------- // 块级作用域let 和 const 只在 {} 内部有效 function blockScope() { { let blockVar 我只在这里; const blockConst 我也只在这里; console.log(blockVar); // ✅ 可以访问 } // console.log(blockVar); // ❌ 编译错误找不到变量 } // 对比 var没有块级作用域 function noBlockScope() { { var x 我会逃逸出去; } console.log(x); // ✅ 居然能访问这就是问题所在 }这个你应该很容易理解同步版本会立即执行因此依次输出 0、1、2。没有问题每次打印时 i 恰好就是当时的值。二、那代码改成异步后呢var i; for (i 0; i 3; i) { setTimeout(() { console.log(i); // ← 过 3 秒才打印 }, 3000); } // 输出3, 3, 3 ❌ // 把这里的var 改成 let for (let i 0; i 3; i) { setTimeout(() { console.log(i); }, 3000); } // 输出0, 1, 2 ✅那么问题来了为什么用 let 就能正常打印而用 var 却不行呢let 的情况 var 的情况 ┌───────────────┐ ┌───────────────┐ │ 块1: i 0 │ │ │ │ setTimeout() │ │ var i │ └───────────────┘ │ (共用一个) │ ┌───────────────┐ │ │ │ 块2: i 1 │ │ │ │ setTimeout() │ │ │ └───────────────┘ │ │ ┌──────────────- │ │ │ 块3: i 2 │ │ │ │ setTimeout() │ │ │ └───────────────┘ └───────────────┘ 3 个独立的 i 只有 1 个 i用一张图说明let 在 for 循环里JS 引擎自动给每一圈循环 套了一个独立的 {} 块 相当于每次循环都重新声明了一遍 i 。所以 3 个回调各看各的 i 互不干扰。而var 的i只有1个3次循环都在改同一个i。1、let循环执行时js引擎实际干的事// 第 1 次循环 { let i 0; setTimeout(() console.log(i), 3000); } // 第 2 次循环 { let i 1; setTimeout(() console.log(i), 3000); } // 第 3 次循环 { let i 2; setTimeout(() console.log(i), 3000); }2、var循环执行时js引擎却是如下var i; // ← 只有一个在循环外面 i 0; setTimeout(() console.log(i), 3000); i 1; setTimeout(() console.log(i), 3000); i 2; setTimeout(() console.log(i), 3000); i 3; // 循环结束后 i 变成 33、那如果就是要用var呢怎么修改代码才能打印出 0,1,2是不是在执行的时候让函数立即执行ImmediatelyInvokedFunctionExpression就行了呢那么就引入了IIFE 闭包两个概念的组合了。(function() { // 代码... })(); // 注意这个 ()定义完立刻调用 // 解释 // fn() 执行fn函数 // 这里 fn 就是 function() {} // 也就是立即执行了 // 再看文章最开始的代码 // 2、 IIFE 闭包 for (var i 0; i 3; i) { (function(index) { setTimeout(() { console.log(index); }, 100); })(i); } // 理解了吧 立即执行fn(i) 就是执行 i是实参index是形参 // 这里i立即传给函数了所以 i是0 -》1 -》 2 function(index) { setTimeout(() { console.log(index); }, 100); }就像你写了个匿名函数不等别人来调当场就执行闭包 函数等“记住”并访问它所在的作用域即使函数在外面跑。组合起来是什么用 IIFE 创建一个 独立的私有作用域 里面的函数引用了外部变量就形成了 IIFE 闭包。最经典的例子// 用 IIFE 闭包实现计数器不污染全局变量 const counter (function() { let count 0; // 私有变量外面碰不到 return { increment() { count; return count; }, reset() { count 0; } }; })(); // ← 立刻执行 counter.increment(); // 1 counter.increment(); // 2 // count 变量永远是 0 吗不它被闭包记住了大白话类比概念类比IIFE你开了一间旅馆房创建了一个独立空间 开完立刻就进去 立即执行闭包你在房间里写了张纸条记着房号退房后纸条还在变量被记住了IIFE闭包开了房 → 立刻进去 → 做了些事 → 走的时候把房间号记在小本本上带走 → 下次来还能接着用实际用途1. 封装私有变量 — 不让外部直接访问内部状态2. 避免命名冲突 — 每个 IIFE 都是独立的小空间3. 循环绑定事件 — 经典的 for 循环 setTimeout 问题简单说 IIFE 是手段闭包是结果 组合起来就是「用一个一次性的函数创建出有持久记忆的私有空间」码字不易点个赞再走吧~~~
RELATED

相关推荐

中项-案例分析2

中项-案例分析2

规划质量管理过程中可用来规避该问题的工具 / 技术: 1. 过程决策程序图 (PDPC) 这是一种系统性的管理规划工具,旨在识别正在制定的计划中可能出现的问题。通过该工具,团队可以提前制定对策来预防或抵消这些问题,从而修订计划以避开…

📅 2026/11/5 6:46:46
工业数据采集网关架构设计

工业数据采集网关架构设计

工业数据采集网关架构设计一套 C17 插件化工业数据采集网关的设计思路与关键实现 版本 v1.0一、为什么用插件化架构 工业现场的设备协议极多:Modbus TCP、OPC UA、串口私有协议、UDP 报文、HTTP/JSON…… 如果每接一种协议就改一次内核,项目会迅速失控。…

📅 2026/11/5 6:46:46
电工基础自学笔记

电工基础自学笔记

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/11/5 6:46:46
MORE NEWS

更多资讯

📰

物联网视频融合平台架构与关键技术解析

1. 物联网视频融合平台的现状与挑战在当今万物互联的时代,视频数据已成为物联网感知层最重要的信息载体之一。据统计,全球物联网设备产生的视频数据量正以每年40%的速度增长,但同时也面临着三大核心痛点:协议碎片化问题&#xff1…

📰

VMware Ubuntu网络问题排查与解决指南

1. 问题现象与初步排查最近在VMware Workstation Pro 17上安装Ubuntu 22.04 LTS时遇到了网络连接问题。主机是Windows 11系统,能正常上网,但虚拟机里的Ubuntu却显示网络不可用。这种问题在实际开发环境中很常见,特别是刚接触虚拟化的开发者。…

📰

XD转Sketch的三种可靠方法:保真、可控与自动化

1. 项目概述:为什么“XD转Sketch”至今仍是设计协作中的高频痛点“XD文件转换为sketch的三种方法”——这个标题看似简单,实则背后牵扯的是国内大量中小型设计团队、外包工作室乃至独立设计师在真实工作流中反复踩坑、反复试错、反复妥协的缩影。我接触过…

📰

商业分析AI工具横评:9大平台实战对比与选型指南

1. 项目背景与核心价值作为一位在商业分析领域深耕多年的从业者,我深知MBA学员和商业分析师在选择AI工具时面临的困境。市面上号称能"降低AI使用门槛"的平台层出不穷,但真正经得起实战检验的却寥寥无几。这次我耗时三个月,自费测试…

📰

工业智能化转型:核心技术架构与实战应用

1. 工业智能化转型的必然趋势十年前走进工厂车间,你会看到流水线上密密麻麻的工人重复着机械动作;如今同样场景里,机械臂的轨迹比老师傅更精准,视觉检测系统比质检员更敏锐。这种变革背后是工业领域正在经历的三重颠覆&#xff1a…

📰

AD封装库全流程:原理图库、PCB库与3D库管理避坑

简介:面向Altium Designer用户的元器件库合集,覆盖原理图绘制到PCB布局布线的常见需求,适合刚入门AD、需要快速补齐基础库的电子工程师与在校学生,也便于有经验的设计者减少重复建库。压缩包共117个文件,约464.27MB&am…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬