前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库IIFE 立即执行函数 用途
JavaScript函数与作用域

什么是 IIFE?现在有了 let 和模块,它还有什么用?

IIFE 就是定义完立刻调用的函数,写法是 (function () { ... })()。以前 JavaScript 只有函数能隔出作用域,大家就用它把变量包起来,不污染全局。现在变量隔离交给 let 和模块了,它主要用在一次性初始化和 async 入口这些地方。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#函数与作用域
先看核心答案读代码示例
理解线索

IIFE 的三个作用

  1. 隔离变量函数体是独立作用域,里面声明的变量外面访问不到
  2. 私有状态返回的方法通过闭包读写内部变量,外部只能走这些方法
  3. 一次性执行只跑一次,把结果交给外面的变量,过程中的临时变量随之丢弃

IIFE 跑完之后,没被返回的函数引用的局部变量就可以回收了;被返回的方法引用着的变量会一直活着,这就是闭包。

核心回答

先记住这个答案

IIFE(Immediately Invoked Function Expression)是定义之后立刻执行的函数表达式,比如 (function () { var a = 1 })()。外层那对括号的作用是让解析器把 function 当成表达式而不是声明,这样后面才能接 () 直接调用。它的用途主要有三个:隔离变量不污染全局、用闭包保存私有状态、把一段只跑一次的初始化逻辑包起来。在 let、const 和 ES 模块普及之前,它是 JavaScript 里模块化的主要手段。

  • 外层括号让 function 被当成表达式,才能直接调用
  • 里面的 var 和函数不会漏到外面
  • 返回函数时,闭包能留住私有状态
  • 现代用法:async IIFE、一次性计算初始值

用 IIFE 做一个带私有状态的模块

jQuery 时代很多库都是这么写的:一个 IIFE 包住全部代码,只把公开的方法返回出去。

计数器模块JavaScript
const counter = (function (initial) {
  let count = initial // 外面访问不到
  return {
    increment() {
      count += 1
    },
    value() {
      return count
    }
  }
})(10) // 立即调用,传入初始值

counter.increment()
console.log(counter.value())
console.log(typeof count) // 外层根本没有 count
查看输出与解释
11
undefined

函数只执行了一次,执行完 count 本应随之销毁,但返回的 increment 和 value 还引用着它,所以它一直保留在闭包里。外面拿到的 counter 只有两个方法,想改 count 只能通过 increment,这就是所谓的模块模式。 参数 initial 也是常见用法。以前的库经常写成 (function ($, window) { ... })(jQuery, window),把全局对象当参数传进去,函数内部用短名字访问,还能防止外面改了 $ 影响内部。

为什么必须加括号

一行以 function 开头时,解析器会把它当成函数声明。函数声明必须有名字,而且声明后面不能直接跟 () 调用,所以 function () {}() 会直接报语法错误。

其它让它变成表达式的写法
只要让 function 出现在「期望一个值」的位置,它就是表达式。括号包住整个函数 (function () {})() 和括号包到调用后面 (function () {}()) 效果一样。前面加一元运算符也行,比如 !function () {}()、void function () {}(),压缩后的库代码里经常见到这种写法,因为能省一个字符。
开头的分号是做什么的
老项目里常见 ;(function () {})()。如果上一个文件末尾没写分号,拼接之后会变成 a = b(function () {})(),上一行的值被当成函数来调用,直接报错。前面补一个分号就能把两段代码隔开。现在用打包工具和格式化工具,这个问题已经很少遇到。

现在还在用的场景

变量隔离这件事,现在用一对花括号加 let 就能做到,文件级别的隔离有 ES 模块。所以 IIFE 不再是必需品,但下面几种场景仍然顺手。

第一种是 async IIFE。在不支持顶层 await 的环境里,比如 CommonJS 的 Node 脚本,常写 (async () => { await main() })() 来获得一个能用 await 的入口。注意它返回的是 Promise,错误要用 .catch() 接住,否则会变成未处理的拒绝。

第二种是一次性计算一个常量。比如 const config = (() => { ... return result })(),把中间用到的临时变量关在函数里,外面只留一个 const,比先声明 let 再在后面赋值更清楚。

回答前,多想一步

容易答错的地方

以为 IIFE 执行完所有变量都释放了
没被引用的局部变量会释放,被返回的函数引用着的变量会一直存活。模块模式能工作,靠的就是这一点。
把 IIFE 当成安全沙箱
IIFE 只隔离变量名,里面的代码照样能访问 window、修改全局对象、发请求。它解决的是命名冲突,不是安全隔离。
试着用自己的话回答

面试官还会怎么问?

块级作用域能完全替代 IIFE 吗?

单纯隔离变量可以,{ let a = 1 } 就够了。但块不能接收参数,也不能返回值。需要把计算结果交给外层变量、或者要用 await 的时候,IIFE 还是更方便。

IIFE 和 ES 模块有什么区别?

IIFE 靠函数作用域隔离,对外暴露内容要么返回,要么挂到全局变量上,依赖关系全靠加载顺序。ES 模块本身就是独立作用域,用 import 和 export 明确声明依赖,打包工具可以据此做静态分析和 tree shaking。

箭头函数能写 IIFE 吗?

能,写成 (() => { ... })(),括号必须把箭头函数整个包住。它和普通函数 IIFE 的区别在于没有自己的 this 和 arguments,会用外层的。

从一道题,走向一组知识

把知识连起来

函数与作用域

箭头函数写的 IIFE 和普通函数写的 IIFE 有什么区别?

用箭头函数也能写 IIFE,区别在里面的 this 和 arguments 从哪里来。

函数与作用域

函数的 length 是什么?加了默认参数和剩余参数后会变吗?

早期依赖注入框架靠读函数形参做注入,形参信息和 length 一样是函数自带的元数据,重构参数时都容易踩坑。

参考资料

  • IIFE - MDN Glossary

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 用 IIFE 做一个带私有状态的模块
  3. 为什么必须加括号
  4. 现在还在用的场景
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑