当前位置: 首页 > news >正文

立即执行函数(IIFE)

深入理解 JavaScript 的 IIFE

什么是 IIFE

IIFE(立即执行函数表达式),指的是定义后立即执行的函数表达式。它的核心价值在于 创建一个独立的作用域(scope),把临时变量、初始化逻辑、私有状态封装起来,避免污染外部(通常是全局)命名空间。

最常见的形式长这样:

(function () {// 私有作用域const secret = 42;console.log('初始化完成');
})();

或者等价写法:

(function () {// ...
}());

为什么不直接写 function(){ ... }()?因为 function(){} 在开头是 函数声明(function declaration),语法上不能直接被“调用”;把它放在括号里或用其他运算符强制把它当作 表达式(expression),这样就能立即调用。


基本语法变体

常见写法有几类:
在这里插入图片描述

要点

  • function 放在表达式上下文(例如 () 或一元运算符)中,保证它是函数表达式而非函数声明。
  • 箭头函数也能做 IIFE,但仍需包在 () 里或置于能形成表达式的位置。

IIFE 能解决哪些问题?

  1. 避免全局污染:把临时变量、辅助函数限制在 IIFE 内。
  2. 模块封装(早期模块化):在 ES Modules 出现前,IIFE 常被用来模拟模块(reveal module pattern)。
  3. 初始化逻辑:页面或库的启动代码放到 IIFE,保证只运行一次并隐藏内部实现。
  4. 闭包创建与数据私有化:返回一个对象或函数,外界只能通过暴露的接口访问私有数据。
  5. 捕获循环变量(旧时用法):在 var 循环中用 IIFE 捕获当次循环的变量值(ES6 let 后常不再需要)。

示例 —

const Counter = (function() {let n = 0; // 私有function inc() { n++; }function get() { return n; }return { inc, get }; // 暴露
}());Counter.inc();
console.log(Counter.get()); // 1

深入:IIFE 与闭包、内存、以及生命周期

  • 闭包:IIFE 返回函数或对象并将私有变量保在闭包中。这些私有变量会被 JavaScript 引擎保留,直到没有任何引用存在为止。
  • 内存泄露风险:如果 IIFE 创建的闭包持有对大量外部资源(DOM 节点、大数组)的引用且长期存在,会增加内存占用。规范做法:不要在长期存活的闭包中保留不必要的大对象;必要时提供 destroy() 方法断开引用。
  • 垃圾回收:一旦外部对 IIFE 返回对象的引用被清除,闭包内的私有数据即可被回收。

进阶用法与细节(必读)

1. 命名函数表达式的优势

(function fact(n) {if (n <= 1) return 1;return n * fact(n - 1);
})(5);

这不是函数声明,而是命名函数表达式fact 名只在函数内部可见,便于递归和调试。

2. 函数声明 vs 函数表达式 —— 常见误区

function foo(){ }(); // SyntaxError —— 这是函数声明,不能直接调用
(function foo(){ }()); // OK

3. 自动分号插入,引起的问题

如果上一行代码没有分号,紧接着写 IIFE 可能被解析到上一行上,导致难以察觉的 bug。常见解决办法:在 IIFE 前加分号(防御性分号):

// 假设上一行没有结束分号
const a = 1
;(function(){ /* safe IIFE */ })()

4. generator IIFE

const g = (function* () {yield 1;yield 2;
})();console.log(g.next());
console.log(g.next());
console.log(g.next().done);

在这里插入图片描述

注意:(function*(){})() 返回生成器对象,(生成器对象就是一个迭代器),不是直接迭代结果。

迭代器

//这是一个简易的迭代器
const iterator = {count: 0,next() {if (this.count < 3) {return { value: this.count++, done: false };}return { value: undefined, done: true };}
};
console.log(iterator.next()); // { value: 0, done: false }
console.log(iterator.next()); // { value: 1, done: false }

生成器对象

function* fibonacci() {let a = 0, b = 1;while (true) {yield a;// yield b;[a, b] = [b, a + b];}
}
const fib = fibonacci();
for(let i = 0;i < 10;i++){console.log(fib.next().value); 
}

每次调用 next() 方法时,生成器会在 yield a 处暂停并产出当前的斐波那契数,然后继续执行循环计算下一个数,从而实现 “按需生成、无限迭代” 的效果
在这里插入图片描述

5. 用 IIFE 捕获循环变量

let j = 0;
for (var i = 0; i < 5; i++) {setTimeout(function () {console.log(`${j+1}次打印`);j++;console.log(i);}, 1000 * i);
}

打印结果:
在这里插入图片描述

示例分析:

for (var i = 0; i < 5; i++) {// 赋值 setTimeout(function() { console.log(i) }, 1000 * i)// i 1,2,3,4,5
}
// setTimeout 延迟执行,var i被统一赋值为5
setTimeout(function () {console.log(5);
}, 1000 * 0);
setTimeout(function () {console.log(5);
}, 1000 * 1);
setTimeout(function () {console.log(5);
}, 1000 * 2);
setTimeout(function () {console.log(5);
}, 1000 * 3);
setTimeout(function () {console.log(5);
}, 1000 * 4);

ES5 示例(var):

通过作用域来保护,用块级作用域来保护 i

for (var i = 0; i < 3; i++) {(function(i) {setTimeout(function(){ console.log(i); }, 0);})(i);
}
// 输出 0 1 2

ES6 用 let 更简洁:

for (let i = 0; i < 3; i++) {setTimeout(() => console.log(i), 0);
}

测试一下

1.
(function () {if (typeof name === 'undefined') {console.log('Goodbye ' + name);} else {var name = 'Jack';console.log('Hello ' + name);}
})();

解析:var name 被提到函数顶部,且默认为 undefined

2.
var _fn = function () {console.log(1);
};(function () {var _fn = function () {console.log(2);};var fn1 = function () {this._fn.apply(this);};var obj = {_fn: function () {console.log(3);},fn2: fn1.bind({_fn: function () {console.log(4);},}),fn3: fn1,};var fn4 = obj.fn3;var fn5 = obj.fn2;fn1();obj.fn2();obj.fn3();fn4();this.fn5();//在 IIFE(非箭头函数)中,顶层的 this:严格模式下 → undefined,非严格模式下 → 指向全局对象(window)
})();

解析:
在这里插入图片描述

题目来源:深入理解JavaScript——立即执行函数(IIFE)

http://www.dtcms.com/a/596587.html

相关文章:

  • Scratch编程教程 | 从入门到实战创意编程
  • 如何在Keil5中在没有硬件支持的情况下使用Keil的模拟器(Simulator) + 调试窗口输出进行调试
  • YOLOv8改进实战:自研MSAM多尺度注意力机制,通道注意力全面升级,CBAM再进化!
  • 从一场年会看乐鑫科技的创新传承
  • 【系统架构设计师-2025下半年真题】综合知识-参考答案及详解(回忆版)
  • custed谁做的网站大连电商平台有哪些
  • 公司高端网站设计公司沈阳建设厅官方网站
  • 微信小程序必要要安装SSL证书吗?小程序SSL详解
  • PostgreSQL18新功能COPY命令变得更加用户友好
  • 医疗小程序05完善就诊人信息
  • idea AI编程 腾讯云代码助手 CodeBuddy插件安装和使用
  • 湖南益阳网站建设做地坪网站
  • 02-SQLite 为了防止多人同时乱写,把整个数据库文件“当一本账本加锁”
  • 盲盒抽赏小程序一番赏 + 无限赏拓展玩法分析:技术赋能与商业破局
  • 专业网站开发价格wordpress打开自定义很慢
  • 济南建站公司电话网页界面设计与制作邓文达
  • Mysql主从架构的搭建
  • MySQL数据库:表的增删改查 [CRUD](进阶)
  • AI+云计算互融共生,2025AI云产业发展大会即将举行
  • 基于YOLO的深度学习框架用于从胸部X射线图像检测肺炎
  • spring cloud微服务常用组件
  • 工业通信的“钢铁心脏”:耐达讯自动化Profibus光纤模块,为机械手臂提供持久动力
  • 【Kafka全攻略】Kafka从入门到实战:核心概念+实操配置+故障排查全攻略
  • 基于SpringBoot的新闻管理系统【协同过滤推荐算法+可视化统计】
  • 展示型网站方案C语言做网站需要创建窗口吗
  • 电脑硬盘数据恢复原理及核心技术解析
  • 潍坊网站建设制作几分钟弄清楚php做网站
  • Hadoop在AI时代如何实现生态协同? CMP 7.13(或类 Cloudera CDP7.3 的 CMP 7.13 平台,如华为鲲鹏 ARM 版)
  • 麒麟系统离线安装Rabbitmq
  • 【大模型训练】megatron分布式并行训练的调用流程,关键函数forward_backward_func