JavaScript 中的 IIFE 是什么?

2025 年 8 月 5 日 | 阅读 9 分钟

IIFE 的基本原理

在 JavaScript 中,一个被称为立即执行函数表达式 (IIFE) 的函数在定义后会立即执行。这种 IIFE 的设计模式也称为自执行匿名函数。它们与常规函数不同,因为 IIFE 在定义后立即调用,而常规函数在定义后需要显式调用。IIFE 的主要作用是在本地作用域中定义变量和函数,以防止全局作用域被污染。

IIFE 语法

IIFE 的语法与常规函数声明略有不同。在典型的JavaScript函数中,我们使用 function 关键字后跟名称、参数以及一对花括号包围的代码块,但 IIFE 使用特殊的语法,通过该语法函数在定义后立即调用。

IIFE 的基本语法如下

或者使用 ES6 箭头函数语法

在这两种情况下,函数都用括号 () 包裹,这使其成为一个函数表达式。之后,另一对括号 () 用于立即调用该函数。

常规函数声明和 IIFE 之间的重要区别在于,常规函数通常有一个名称,并且必须显式调用才能执行,而 IIFE 通常是匿名的,这意味着它没有名称,并且在定义后立即被 JavaScript 解释器调用。

IIFE 的演变和历史背景

早期 JavaScript 对 IIFE 的需求

JavaScript 最初是为了在网页中提供交互性而开发的。随着网站变得越来越复杂,开发人员肯定需要更复杂的策略来控制作用域和防止全局命名空间污染。在全局作用域中声明的 JavaScript 变量或函数可以在代码的任何地方访问,这增加了名称冲突和意外错误的风险,尤其是在可能同时执行多个脚本时。

IIFE 的引入

为了解决这些问题,开发人员开始使用 IIFE 来为变量和函数创建私有作用域。通过将代码包含在 IIFE 中,它们可以确保 IIFE 中的变量不会泄露到全局作用域。因此,IIFE 成为开发模块化 JavaScript 代码的必要工具,尤其是在现代模块系统出现之前。

模块模式和 IIFE

一种称为模块模式的设计模式,它将代码分组为可重用和自包含的单元。它将代码的某些部分保持私有,而将其他部分暴露给公共接口。在 ES6 引入原生的 JavaScript模块之前,IIFE 被广泛用于实现模块模式。

简而言之,我们可以说 IIFE 是开发人员用来构建 JavaScript 模块的工具。它有助于返回一个具有公共方法的对象,同时将内部变量和函数隐藏在全局作用域之外。

深入探究 IIFE 的变体和语法

IIFE 语法

闭合括号

括号的使用是 IIFE 语法的一个基本组成部分。函数本身被一对括号包围,原因是 JavaScript 应该区分函数表达式和函数声明。JavaScript 引擎将函数读取为表达式,而不是声明。

使用函数

在上面的 IIFE 语法中,在函数表达式之后,还有另一对括号。第二对括号立即调用函数。因此,函数很快就开始执行。

IIFE 语法中的变体

IIFE 的语法有几种版本,每个版本都能完成相同的事情,但外观略有不同。其中一些如下

整个 IIFE 周围的括号

使用一元运算符

在此变体中,一元运算符,如 **!** 或 **+**,放在函数前面,这使得 JavaScript 将函数解释为表达式而不是声明。

这些变体虽然不太常见,但却展示了 JavaScript 语法的强大功能。

参数化 IIFE

开发人员可以为 IIFE 提供参数,以便在调用函数时使用它们。使用此功能,您可以创建可重用和可定制的代码块。

代码

输出

Hello, World!

说明

在此示例中,IIFE 接收字符串 **"Hello, World!"** 作为参数,并在执行后立即将其记录到控制台。

IIFE 的应用

作用域隔离

创建新作用域是 IIFE 的一项基本用途。在 JavaScript 中使用 **var** 关键字定义的变量是函数作用域的。如果 **var** 在函数外部使用,它将变成全局变量。通过保持变量隔离,IIFE 有助于防止对全局作用域的意外干扰。

代码

输出

10
ReferenceError: x is not defined

说明

在这种情况下,变量 **x** 仅限于 IIFE 并且不影响全局作用域。当在作用域内调用 **x** 时,它会产生输出,但当在作用域外调用 **x** 时,它会产生错误。

防止全局命名空间污染

在大型 JavaScript 应用程序中,很容易意外地覆盖全局变量或函数,这可能导致错误和不可预测的行为。IIFE 通过将代码封装在本地作用域中,有助于防止全局命名空间中的错误。

代码

输出

Local
Global

创建闭包

IIFE 通常用于开发闭包,闭包是 JavaScript 的一个概念,其中内部函数即使在外部函数执行完成后,仍然可以访问其外部函数的变量。这有助于私有地保存数据。

代码

输出

1
2
3

模块模式和模块化

在引入ES6 模块之前,JavaScript 模块化编程通常使用 IIFE 编写。这种模式允许封装,这意味着将某些变量或函数设为私有,同时只显示必要的部分。

代码

输出

I am private
undefined

IIFE 的优点

What is IIFE in JavaScript

1. 避免全局命名空间污染

IIFE 的一个重要好处是它阻止了全局作用域的污染。在 JavaScript 中全局声明的变量和函数有可能产生错误,尤其是在具有多个脚本的大型结构中。通过 IIFE,变量和功能被封装在本地作用域中,这可以防止它们泄露到全局命名空间。

2. 数据隐私封装

IIFE 可防止外部访问其中定义的变量。这种封装允许程序员创建私有变量和函数,保护代码的内部逻辑并防止外部代码的意外干扰。

3. 即时执行

IIFE 在定义后立即执行,这在需要设置事件监听器、配置或其他一次性初始化逻辑时特别有用,这些逻辑应该在脚本加载时立即运行。

4. 避免副作用

IIFE 在自己的作用域中运行,因此它们不会运行作用域外的代码。这种隔离可以通过阻止意外的副作用来提高代码的可靠性。

5. 与旧版 JavaScript 的兼容性

在 ES6 引入letconst之前,JavaScript 只有函数作用域而没有块作用域。IIFE 可以在不需要现代块作用域声明的情况下创建隔离的作用域,这就是 IIFE 与旧版 JavaScript 兼容的原因。

6. 自包含模块

IIFE 有助于创建自包含模块,这意味着它可以封装一部分逻辑并仅返回必需的部分,从而促进了模块化。

IIFE 的缺点

What is IIFE in JavaScript

1. 可读性和复杂性

如果开发人员不熟悉此模式或刚接触 JavaScript,IIFE 的语法可能看起来很复杂。初学者可能难以将函数封装在括号内并立即调用它。IIFE 的不同样式可能会使代码难以阅读,并且在大型代码库中过度使用 IIFE 会降低可读性。

2. 作用域管理挑战

IIFE 中的变量在本地作用域中声明,无法从外部访问。有时,当 IIFE 很大或包含深度嵌套的逻辑时,跟踪变量会变得困难。

过度使用 IIFE 可能导致过度隔离,从而使维护 IIFE 变得困难,因为开发人员可能需要通过多层 IIFE 来理解组件之间的交互。

3. 代码重复

对于每个 IIFE,都有括号和立即调用函数等重复的语法,这会导致样板代码。当多个 IIFE 包含相似的逻辑时,它们容易出错并且维护起来很麻烦。

在 IIFE 中声明的变量和函数在函数块外部不可访问,因此无法在其他地方重用,但在其他地方创建相同的逻辑块会增加重复和不必要的代码量。

4. 调试困难

由于作用域的隔离,调试 IIFE 中的代码可能会更困难。当 IIFE 很大或很复杂时,跟踪 IIFE 中的变量和函数很困难。匿名 IIFE 可能会产生难以解释的堆栈跟踪,这使得确定错误的精确位置变得复杂,从而增加了调试时间。

5. 性能方面

众所周知,IIFE 会立即运行代码,如果其中的代码不需要立即执行,则可能会导致不必要的开销。IIFE 通过限制作用域来帮助管理内存,但它们可能会因立即执行和后续内存清理而影响性能。

6. 被现代 JavaScript 功能淘汰

IIFE 并非完全过时,但在现代 JavaScript 中使用较少,因为新功能提供了更好的替代方案。IIFE 的主要目的是避免全局命名空间污染并创建私有变量和本地作用域,但在 ES6 之后,函数可以具有块作用域,从而取代了 IIFE 的大多数用途。随着箭头函数的引入,IIFE 的需求减少了,因为箭头函数提供了更简洁的语法。

常见问题解答 (FAQs)

1. 什么是 IIFE?

在 JavaScript 中,**立即执行函数表达式**是 IIFE 的完整形式。它是一个 JavaScript 函数,在定义后立即执行。它使我们能够封装代码并创建私有作用域。因此,变量是分开的,它防止了与其他代码部分的干扰。

语法

2. IIFE 有哪些用途?

IIFE 有许多用途。其中一些如下

  • 它对于在 JavaScript 中创建闭包很有用。
  • 它对于创建私有和公共变量很有用。
  • 它帮助我们避免污染全局命名空间。
  • 它对于执行 **async** 或 **await** 函数很有用。

3. 匿名 IIFE 和命名 IIFE 之间有什么区别?

命名 IIFE 在括号内有一个函数表达式的名称。它对于调试和递归很有用。匿名 IIFE 没有名称,但在现代编程中,匿名函数比命名 IIFE 更常见。

4. IIFE 在避免全局作用域污染方面有什么好处?

在 IIFE 中,在 IIFE 内部定义的变量和函数是本地作用域的,这意味着无法从外部访问它们。它降低了意外覆盖或与全局作用域变量发生冲突的风险。

5. IIFE 可以接受参数吗?

是的,IIFE 可以像常规函数一样接受参数。

语法

6. IIFE 如何帮助实现 JavaScript 中的模块模式?

模块模式利用 IIFE 来创建私有变量和方法,然后为开发人员提供一个公共接口,外部世界可以使用该接口与那些私有变量/方法进行交互。

7. 在 IIFE 的上下文中解释闭包概念。

IIFE 通常会创建闭包,允许在 IIFE 内部定义的函数在 IIFE 执行完成后仍然记住并访问 IIFE 作用域中的变量。

8. IIFE 如何用于防止变量提升问题?

当变量封装在 IIFE 的作用域内时,其提升行为仅限于该本地作用域,从而防止了意外的全局交互。

9. 何时选择 IIFE 而不是标准函数声明?

我们可以选择 IIFE 而不是标准函数声明,原因如下

  • 当我们只需要立即执行一次代码时。
  • 当我们想要为变量创建私有作用域以防止全局作用域污染时。