先来看下面这几段 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 是手段闭包是结果 组合起来就是「用一个一次性的函数创建出有持久记忆的私有空间」码字不易点个赞再走吧~~~
企业数字化 ERP 产品动态
相关推荐
中项-案例分析2 规划质量管理过程中可用来规避该问题的工具 / 技术:
1. 过程决策程序图 (PDPC)
这是一种系统性的管理规划工具,旨在识别正在制定的计划中可能出现的问题。通过该工具,团队可以提前制定对策来预防或抵消这些问题,从而修订计划以避开… · 2026/11/5 6:46:32
工业数据采集网关架构设计 工业数据采集网关架构设计一套 C17 插件化工业数据采集网关的设计思路与关键实现
版本 v1.0一、为什么用插件化架构
工业现场的设备协议极多:Modbus TCP、OPC UA、串口私有协议、UDP 报文、HTTP/JSON……
如果每接一种协议就改一次内核,项目会迅速失控。… · 2026/11/5 6:46:32
电工基础自学笔记 /* 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:32
ADS122U04+PIC18F46K42:高精度PT1000测温模块设计与实现 /* 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 7:36:44
基于ADS122U04IPWR与STM32F765ZI的工业及HVAC高精度温度测量方案 /* 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 7:36:44
ADS122U04+PIC32MZ:HVAC高精度温度采集系统设计与实现 /* 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 7:36:44
ADS122U04IPWR+STM32F031C6工业温度测量方案解析 /* 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 7:36:44
基于ADS122U04与PIC32MZ的高精度温度采集系统设计 /* 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 7:36:44
ADS122U04与STM32F410RB工业温度采集方案:UART接口ADC实战详解 /* 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 7:35:44
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38
多智能体协作系统架构设计与实践优化 1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中… · 2026/11/5 0:00:39
大模型系统性入门实战指南:从原理到部署微调的全链路路线 提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#… · 2026/11/5 0:00:39
鸿蒙文件系统沙箱机制解析与开发实践 1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的… · 2026/11/5 0:00:39
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38