立即执行函数
立即执行函数 ( 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+ 提供了更优雅的解决方案:
私有作用域
// 使用块级作用域 + 闭包
{
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);
总结对比
立即执行函数
https://halo.jiangling.site/archives/IIFE