Day2 完整学习包(闭包 & 立即执行函数)——2026 0311

一、核心知识点(30 分钟吃透)

1. 闭包核心原理

  • 定义:函数嵌套时,内部函数引用外部函数的变量 / 参数,且内部函数被外部访问,导致外部函数执行上下文不被销毁,形成闭包。
  • 本质:作用域链的特殊表现 ------ 延长了外部函数变量的生命周期。
  • 关键条件
    1. 函数嵌套(内外层函数);
    2. 内层函数引用外层函数的变量 / 参数;
    3. 内层函数被外层作用域之外的地方调用。

2. 立即执行函数(IIFE)

  • 定义:声明后立即执行的函数,ES5 中主要用于创建独立作用域,避免变量污染(ES6 后可被块级作用域替代,但仍需掌握)。

  • 语法

    js

    复制代码
    // 两种常用写法
    (function() { /* 代码 */ })(); 
    (function() { /* 代码 */ }());
  • 核心作用:隔离作用域,防止变量泄露到全局(如早期 jQuery 源码大量使用)。

3. 闭包的用途、优缺点

表格

核心用途 优点 缺点
1. 保存私有变量(模块化) 变量私有化,避免全局污染 变量不销毁,长期占用内存
2. 延长变量生命周期 可缓存数据,减少重复计算 滥用易导致内存泄漏
3. 实现柯里化 / 防抖节流 增强函数灵活性,复用逻辑 调试难度增加(作用域链复杂)

二、手写闭包案例(40 分钟必练)

案例 1:基础闭包(保存私有变量)

js

复制代码
// 需求:创建计数器,每次调用加1,且计数变量不暴露到全局
function createCounter() {
  let count = 0; // 外层变量,被内层函数引用
  // 内层函数作为返回值,被外部访问,形成闭包
  return function() {
    count++;
    console.log(count);
  };
}
const counter = createCounter();
counter(); // 输出1
counter(); // 输出2
console.log(count); // 报错(count私有化,外部无法访问)

案例 2:闭包实现数据缓存

js

复制代码
// 需求:缓存计算结果,避免重复计算(如斐波那契数列)
function createFibCache() {
  const cache = {}; // 缓存对象,闭包保存
  return function fib(n) {
    if (n <= 2) return 1;
    if (cache[n]) return cache[n]; // 命中缓存直接返回
    cache[n] = fib(n-1) + fib(n-2); // 未命中则计算并缓存
    return cache[n];
  };
}
const fib = createFibCache();
console.log(fib(10)); // 首次计算,缓存结果
console.log(fib(10)); // 直接读取缓存,性能提升

案例 3:立即执行函数 + 闭包(模块化)

js

复制代码
// 需求:模拟模块化,封装用户信息操作,仅暴露指定方法
const userModule = (function() {
  // 私有变量(闭包保存,外部无法直接访问)
  let username = "zhangsan";
  let age = 20;
  
  // 私有方法
  function checkAge() {
    return age >= 18;
  }

  // 暴露公有方法(闭包引用私有变量)
  return {
    getUsername: function() {
      return username;
    },
    setAge: function(newAge) {
      if (newAge > 0) age = newAge;
    },
    isAdult: function() {
      return checkAge();
    }
  };
})();

console.log(userModule.getUsername()); // zhangsan
userModule.setAge(25);
console.log(userModule.isAdult()); // true
console.log(userModule.username); // undefined(私有变量不可访问)

案例 4:闭包实现防抖(高频面试手写题)

js

复制代码
// 需求:防抖函数------频繁触发时,仅最后一次触发生效
function debounce(fn, delay) {
  let timer = null; // 闭包保存timer,延长生命周期
  return function(...args) {
    clearTimeout(timer); // 清除上一次的定时器
    timer = setTimeout(() => {
      fn.apply(this, args); // 绑定this和参数
    }, delay);
  };
}
// 使用示例
const input = document.querySelector("input");
input.oninput = debounce(function(e) {
  console.log("搜索:", e.target.value);
}, 500);

	<script>
			//案例 一:基础闭包(保存私有变量)
			// 需求:创建计数器,每次调用加1,且计数变量不暴露到全局
			function createCounter() {
				let count = 0;
				return function () {
					count++;
					console.log(count);
				};
			}
			const counter = createCounter();
			counter(); // 1
			counter(); // 2
			console.log(count); // 报错(count私有化,外部无法访问)

			// 案例 二:闭包实现数据缓存

			// 需求:缓存计算结果,避免重复计算(如斐波那契数列)

			// 1. 创建缓存工厂函数
			function createFibCache() {
				// cache 是私有变量,外部无法直接访问
				const cache = {};

				// 2. 返回内部函数(形成闭包)
				return function fib(n) {
					// 边界条件:前两个数都是 1
					if (n <= 2) return 1;

					// 3. 缓存命中:直接返回,不用重复计算
					if (cache[n]) return cache[n];

					// 4. 缓存未命中:计算并保存结果
					cache[n] = fib(n - 1) + fib(n - 2);

					return cache[n];
				};
			}

			// 5. 获取缓存函数
			const fib = createFibCache();

			// 6. 首次调用:计算并缓存
			console.log(fib(10)); // 输出 55,同时缓存了 fib(1)~fib(10)

			// 7. 再次调用:直接读缓存,瞬间返回
			console.log(fib(10)); // 输出 55,无需重新计算

			// 案例 三:立即执行函数 + 闭包(模块化)
			// IIFE 创建独立作用域 + 闭包保存私有变量 = 模块化封装,只暴露必要接口,保护内部数据。
			// 需求:模拟模块化,封装用户信息操作,仅暴露指定方法
			const userModule = (function () {
				// 私有变量(闭包保存,外部无法直接访问)
				let username = "zhangsan";
				let age = 20;

				// 私有方法
				function checkAge() {
					return age >= 18;
				}

				// 暴露公有方法(闭包引用私有变量)
				return {
					getUsername: function () {
						return username;
					},
					setAge: function (newAge) {
						if (newAge > 0) age = newAge;
					},
					isAdult: function () {
						return checkAge();
					},
				};
			})();

			console.log(userModule.getUsername()); // zhangsan
			userModule.setAge(25);
			console.log(userModule.isAdult()); // true
			console.log(userModule.username); // undefined(私有变量不可访问)




			// 案例 四:闭包实现防抖(高频面试手写题)

			// 需求:防抖函数------频繁触发时,仅最后一次触发生效
			function debounce(fn, delay) {
				let timer = null; // timer闭包保存timer,延长生命周期
				return function (...args) {
					if (timer) clearTimeout(timer); // // 清除上一次的定时器
					timer = setTimeout(() => {
						fn.apply(this, args); // 延迟执行fn
					}, delay);
				};
			}
			// 示例:实现输入框实时搜索
			const searchInput = document.querySelector("input");
			serchInput.oninput = debounce(function (e) {
				console.log(e.target.value); // 输入框实时搜索
			}, 500);


			// 案例 五:闭包实现节流(高频面试手写题)
			// 需求:节流函数------频繁触发时,仅在一定时间内执行一次
			function throttle(fn, delay) {
				let lastTime = 0; // lastTime闭包保存上次执行时间
				return function (...args) {
					const now = Date.now();
					if (now - lastTime >= delay) {
						fn.apply(this, args); // 执行fn
						lastTime = now; // 更新上次执行时间
					}
				};
			}
			// 示例:实现鼠标移动事件的节流	
			window.onmousemove = throttle(function (e) {
				console.log(e.clientX, e.clientY); // 鼠标移动事件节流
			}, 500);

			// 案例 六:闭包实现函数防重(高频面试手写题)
			// 需求:函数防重------同一时间内,同一函数只执行一次
			function once(fn) {
				let done = false; // done闭包保存执行状态
				return function (...args) {
					if (!done) {
						done = true;
						fn.apply(this, args);
					}
				};
			}
			// 示例:实现按钮点击防重
			const btn = document.querySelector("button");			
			btn.onclick = once(function () {				
				console.log("点击成功"); // 按钮点击防重
			});	
			
			// 案例 七:闭包实现函数缓存(高频面试手写题)
			// 需求:函数缓存------同一函数,缓存执行结果,避免重复执行
			function cached(fn) {
				const cache = {}; // cache闭包保存执行结果
				return function (...args) {
					const key = JSON.stringify(args); // 缓存key
					if (cache[key]) return cache[key]; // 命中缓存,直接返回
					const result = fn.apply(this, args); // 执行函数
					cache[key] = result; // 缓存结果
					return result;
				};
			}
			// 示例:实现数组去重
			const arr = [1, 2, 3, 2, 1, 4, 5, 4, 6, 5];
			const uniqueArr = [...new Set(arr)]; // 去重
			console.log(uniqueArr); // [1, 2, 3, 4, 5, 6]

		
		</script>

三、核心面试题 + 标准答案(20 分钟背会)

面试题:什么是闭包?实际开发中的用途有哪些?

标准答案(高级工程师视角,精简且有深度)
1. 闭包的定义

闭包是 JavaScript 作用域链的特殊表现:当内层函数引用外层函数的变量 / 参数,且内层函数被外层作用域之外的地方调用时,外层函数的执行上下文不会被垃圾回收机制销毁,从而形成闭包。其核心是「延长了外部变量的生命周期,同时实现变量私有化」。

2. 实际开发中的核心用途

(结合业务场景,避免纯理论,体现工程化思维)

  • ① 变量私有化与模块化 :在 ES6 Module 普及前,通过闭包 + 立即执行函数封装模块(如工具库、业务组件),将核心变量隐藏,仅暴露指定方法,避免全局变量污染。例如封装用户信息管理模块,只对外提供getUser/setUser方法,不暴露原始用户数据。
  • ② 数据缓存 / 性能优化:对计算成本高的操作(如大数据遍历、递归计算),用闭包缓存结果,避免重复计算。例如斐波那契数列、商品价格计算缓存。
  • ③ 实现防抖 / 节流 / 柯里化:前端高频交互场景(输入框搜索、窗口 resize、滚动事件)中,用闭包保存定时器(防抖)、触发时间(节流),控制函数执行频率;柯里化则通过闭包保存部分参数,实现函数参数复用。
  • ④ 延长变量生命周期:例如计数器功能,用闭包保存计数变量,每次调用都能基于上次结果更新,且变量不暴露到全局。
3. 加分补充(体现深度)
  • 闭包并非 "漏洞",而是语言特性,合理使用能提升代码封装性;
  • 实际开发中需注意内存管理:使用完闭包后,手动将引用置为null(如timer = null),避免内存泄漏;
  • ES6 后虽可用let/const块级作用域替代部分闭包场景,但闭包仍是实现复杂逻辑(如防抖节流、自定义 hooks)的核心基础。

四、错题整理模板(10 分钟完成)

表格

错题类型 错误代码 / 场景 错误原因 正确思路 / 知识点
闭包内存泄漏 防抖函数中未清空 timer 闭包保存的 timer 一直存在,占用内存 每次触发前清除 timer,不用时置 null
闭包理解偏差 认为 "只要函数嵌套就是闭包" 忽略 "内层函数被外部访问" 条件 闭包必须满足 3 个核心条件
IIFE 使用错误 function(){}()(无括号) 普通函数声明无法直接执行 IIFE 需用括号包裹函数体,触发执行

总结

  1. 核心考点:闭包的定义要紧扣「作用域链 + 变量引用 + 外部访问」,用途需结合业务场景(而非纯理论);
  2. 实战重点:防抖 / 节流、模块化是闭包最核心的业务落地场景,必须能手写;
  3. 易错点:闭包的内存泄漏问题,面试中需主动提及 "合理销毁引用" 的优化方案,体现工程化思维。

闭包必须满足 3 个核心条件

  1. 函数嵌套结构 :必须存在外层函数内层函数的嵌套关系(这是闭包形成的结构基础);
  2. 变量引用关系 :内层函数必须主动引用外层函数的变量 / 参数(而非全局变量,这是闭包形成的核心关联);
  3. 外部访问条件 :内层函数被外层函数的作用域外部调用 / 保存(如作为返回值、赋值给全局变量、传入其他函数),导致外层函数执行上下文无法被垃圾回收(这是闭包能 "生效" 的关键)。

补充(面试加分)

  • 三个条件缺一不可:仅函数嵌套但无变量引用,或仅引用变量但内层函数未被外部访问,都无法形成闭包;

  • 举例验证: js

    复制代码
    // 满足所有条件 → 形成闭包
    function outer() {
      let a = 1; // 外层变量
      return function inner() { // 内层函数被外部访问
        console.log(a); // 内层引用外层变量
      };
    }
    const fn = outer(); 
    fn(); 

总结

  1. 闭包的核心条件聚焦「结构、引用、访问」三个维度,是判断是否形成闭包的关键;
  2. 理解这三个条件,能快速识别代码中的闭包场景,也能解释闭包 "变量不销毁" 的本质原因
相关推荐
南浦别a2 小时前
第三十一天--继续学习--TreeSet排序方式和HashSet
学习
承渊政道2 小时前
C++学习之旅【⽤哈希表封装myunordered_map和myunordered_set以及位图和布隆过滤器介绍】
数据结构·c++·学习·哈希算法·散列表·hash-index·图搜索算法
金山几座2 小时前
C#学习记录-变量与类型
学习·c#
飞Link2 小时前
深度解析 InfoNCE:对比学习背后的“核心功臣”
python·学习·数据挖掘·回归
yangyanping201082 小时前
Linux学习四之 rm 命令详解
linux·运维·学习
怪侠_岭南一只猿2 小时前
爬虫工程师学习路径 · 阶段四:反爬虫对抗(完整学习文档)
css·爬虫·python·学习·html
CappuccinoRose2 小时前
MATLAB学习文档 - 汇总篇
学习·算法·matlab
不灭锦鲤3 小时前
网络安全学习第47天
学习·web安全
zhouping@3 小时前
BUUCTFweb
学习·web安全·php