立即执行函数

立即执行函数 ( IIFE - Immediately Invoked Function Expression ) 在定义后立即执行,核心思想是创建独立作用域,这在模块化/避免命名冲突/封装是有变量方面仍有实用价值

语法

(function () {
  console.log("IIFE执行了!");
})();

// 另一种写法

(function() {
  console.log('IIFE executed');
}());

// ES6 箭头函数写法
(() => {
  console.log('Arrow IIFE executed');
})();

// 赋值表达式写法可以捕获返回值
const result = (function() {
  return 'IIFE with return value';
})();

// 带参数的 IIFE
(function(name, count) {
  console.log(`Hello ${name}, count: ${count}`);
})('Alice', 42);

// 命名IIFE 便于调试,函数有名称时,在堆栈跟踪中会显示函数名
(function myIIFE() {
  console.log('Named IIFE');
  // 在堆栈跟踪中会显示 myIIFE
})();

// void 运算符写法,确保返回 undefined ,较少使用
void function() {
  console.log('IIFE with void');
}();

应用场景

想象你正在整理一个公共图书馆(全局作用域),但有些书籍(变量,函数)不想让人随意触碰,IIFE 就像给这些书加了一个带锁的玻璃柜---能看到他们的存在,但无法直接修改

模块化开发 (ES5时代)


// 模拟jQuery的模块化封装
var myLibrary = (function() {
  // 私有变量 - 就像图书馆的内部登记簿
  var privateConfig = {
    version: '1.0.0',
    maxItems: 100
  };
  
  // 私有方法 - 内部管理流程
  function validateInput(input) {
    return typeof input === 'string';
  }
  
  // 对外暴露的公共API
  return {
    getVersion: function() {
      return privateConfig.version;
    },
    
    process: function(data) {
      if (validateInput(data)) {
        console.log('Processing:', data);
        return true;
      }
      return false;
    }
  };
})();

// 使用
console.log(myLibrary.getVersion()); // "1.0.0"
console.log(myLibrary.privateConfig); // undefined - 无法访问!

避免全局污染


// 多个脚本文件可能冲突的场景
(function() {
  // 这个temp只在当前IIFE内有效
  var temp = calculateComplexValue();
  
  // 初始化页面组件
  initSlider();
  setupModal();
  
  function initSlider() {
    // 使用temp变量
    console.log('Slider initialized with:', temp);
  }
})();

// 另一个脚本中也可以安全使用temp变量
(function() {
  var temp = 'different value'; // 不会冲突!
  console.log(temp); // "different value"
})();

循环中的闭包问题


// 问题:所有按钮都显示"Button 5 clicked"
for (var i = 1; i <= 5; i++) {
  var btn = document.createElement('button');
  btn.textContent = 'Button ' + i;
  btn.onclick = function() {
    alert('Button ' + i + ' clicked'); // i总是6
  };
  document.body.appendChild(btn);
}

// 解决方案:IIFE创建独立作用域
for (var i = 1; i <= 5; i++) {
  (function(index) {
    var btn = document.createElement('button');
    btn.textContent = 'Button ' + index;
    btn.onclick = function() {
      alert('Button ' + index + ' clicked'); // 正确:1,2,3,4,5
    };
    document.body.appendChild(btn);
  })(i); // 立即传入当前i值
}

库的初始化与配置


// 类似jQuery的$别名保护
(function(global, factory) {
  // 支持CommonJS、AMD、全局变量多种加载方式
  if (typeof module === 'object' && module.exports) {
    module.exports = factory();
  } else if (typeof define === 'function' && define.amd) {
    define(factory);
  } else {
    global.MyLib = factory();
  }
})(typeof window !== 'undefined' ? window : this, function() {
  // 实际的库代码
  var version = '2.0.0';
  
  return {
    version: version,
    hello: function() {
      return 'Hello from MyLib v' + version;
    }
  };
});

现代替换方案

ES6+ 提供了更优雅的解决方案:

场景

IIFE 方案

现代方案

私有作用域

(function(){ ... })()

{ ... } 块级作用域

模块化

IIFE + 返回对象

ES6 Modules

循环闭包

IIFE 捕获变量

let + 块级作用域

库封装

IIFE 包装

打包工具 + ES Modules

私有作用域


// 使用块级作用域 + 闭包
{
  let privateCounter = 0;
  const privateConfig = { debug: true };
  
  const privateHelper = () => privateCounter++;
  
  // 创建模块对象
  const myModule = {
    increment: () => privateHelper(),
    getConfig: () => ({ ...privateConfig })
  };
  
  // 如果需要全局访问
  if (typeof window !== 'undefined') {
    window.myModule = myModule;
  }
}

console.log(myModule.increment()); // 0
console.log(myModule.privateCounter); // undefined

模块化->ES6 Modules


// mathUtils.mjs 或 mathUtils.js (type="module")
// 私有函数 - 不导出就是私有的
const validateNumber = (num) => 
  typeof num === 'number' && !isNaN(num);

// 公共API
export const add = (a, b) => {
  if (!validateNumber(a) || !validateNumber(b)) {
    throw new Error('Invalid numbers');
  }
  return a + b;
};

export const multiply = (a, b) => {
  if (!validateNumber(a) || !validateNumber(b)) {
    throw new Error('Invalid numbers');
  }
  return a * b;
};

// 默认导出
export default {
  add,
  multiply
};

// ========== 使用方 ==========
// main.mjs
import { add, multiply } from './mathUtils.mjs';
// 或
import MathUtils from './mathUtils.mjs';

console.log(add(2, 3)); // 5
console.log(MathUtils.multiply(4, 5)); // 20

循环闭包: let + 块级作用域


// 最简单直接的方案
for (let i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log('Modern - let:', i); // 0, 1, 2
  }, 100);
}

// 或者使用forEach(函数作用域)
[0, 1, 2].forEach(i => {
  setTimeout(() => {
    console.log('Modern - forEach:', i); // 0, 1, 2
  }, 100);
});

// 使用块级作用域 + 立即执行箭头函数
for (var i = 0; i < 3; i++) {
  {
    const index = i; // 每次循环创建新的const
    setTimeout(() => {
      console.log('Modern - block scope:', index); // 0, 1, 2
    }, 100);
  }
}

库封装: ES Modules + 打包工具


// src/mylib.js - 纯ES6模块
import dependency from 'dependency';

const version = '2.0.0';
const privateData = new Map();

const privateMethod = () => 'private';

export const publicMethod = () => 
  `${privateMethod()} -> public`;

export const getVersion = () => version;

// 默认导出
export default {
  publicMethod,
  getVersion
};

// ========== 打包配置 (vite.config.js) ==========
export default {
  build: {
    lib: {
      entry: 'src/mylib.js',
      name: 'MyLib',
      formats: ['es', 'umd', 'iife'] // 生成多种格式
    }
  }
};

// 生成的文件自动包含:
// - mylib.es.js (ES模块)
// - mylib.umd.js (UMD格式)
// - mylib.iife.js (IIFE格式,兼容旧浏览器)

立即执行异步操作: 顶层await / 模块初始化


// 方案1:模块顶层await(ES2022+)
// config.js
const configResponse = await fetch('/api/config');
export const config = await configResponse.json();

console.log('Config loaded on module init:', config);

// 方案2:立即执行箭头函数 + async
const initializeApp = async () => {
  const [config, user] = await Promise.all([
    fetch('/api/config').then(r => r.json()),
    fetch('/api/user').then(r => r.json())
  ]);
  
  return { config, user };
};

// 立即执行并处理结果
initializeApp()
  .then(({ config, user }) => {
    console.log('App initialized:', { config, user });
  })
  .catch(console.error);

// 方案3:自执行async函数(更简洁)
(async () => {
  const data = await fetch('/api/data').then(r => r.json());
  console.log('Modern async IIFE:', data);
})();

单次执行代码块: 块级作用域 VS IIFE

//IIFE 单次执行

// 初始化代码只运行一次
(function init() {
  console.log('App initializing...');
  
  // 设置全局配置
  window.APP_CONFIG = {
    env: 'production',
    version: '1.0.0'
  };
  
  // 初始化事件监听
  document.addEventListener('DOMContentLoaded', function() {
    console.log('DOM ready with config:', window.APP_CONFIG);
  });
})();
// 现代方案:模块的副作用


// appInit.js - 模块加载时自动执行
console.log('App initializing...');

// 配置对象
export const APP_CONFIG = {
  env: import.meta.env.MODE, // Vite环境变量
  version: '2.0.0'
};

// 初始化逻辑
const init = () => {
  console.log('Initializing with config:', APP_CONFIG);
  
  // 现代事件监听
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', onDOMReady);
  } else {
    onDOMReady();
  }
};

const onDOMReady = () => {
  console.log('DOM ready with modern config:', APP_CONFIG);
};

// 自动执行
init();

// ========== 使用方 ==========
// main.js
import './appInit.js'; // 导入时自动执行
import { APP_CONFIG } from './appInit.js';

console.log('Config available:', APP_CONFIG);

总结对比

场景

IIFE 方案

现代方案

优势

私有作用域

(function(){ ... })()

{ let/const ... }

语法简洁,符合直觉

模块化

IIFE返回对象

ES6 Modules

静态分析,tree-shaking

循环闭包

IIFE捕获变量

let循环变量

无需额外函数包装

库封装

UMD模式IIFE

打包工具生成

自动化,支持多种格式

异步初始化

async IIFE

顶层await/模块初始化

更清晰的异步流程

代码组织

多个IIFE

模块化拆分

更好的工程化支持


立即执行函数
https://halo.jiangling.site/archives/IIFE
作者
你的降灵
发布于
2026年02月25日
许可协议