JS闭包不理解?一杯咖啡的时间带你轻松理解闭包!

一、为什么闭包很重要?

闭包是JavaScript的灵魂级概念!无论是:

  • 面试高频考点(10个面试9个问)
  • 日常开发(回调函数、模块化、防抖节流)
  • 框架原理(React Hooks、Vue Composition API)

不懂闭包 = 学不好JS

接下来用最通俗的方式帮你彻底掌握!


闭包的优缺点

优点 缺点
封装私有变量,增强数据安全性 过度使用可能导致内存泄漏
实现高阶函数(如柯里化、装饰器) 闭包变量无法被垃圾回收机制释放
解决循环中的异步问题 可能影响代码可读性

二、闭包的生活化比喻

想象你有一个魔法背包🎒:

  1. 装东西:把书本(变量)放进背包(外层函数)
  2. 交给朋友:把背包交给朋友保管(返回内层函数)
  3. 随时取用:朋友即使在你离开后(外层函数执行完毕),仍能打开背包使用书本(访问变量)

三要素

👉 背包里的物品 = 外部函数的变量

👉 获得背包的朋友 = 内部函数

👉 魔法契约 = 闭包规则


三、闭包的双层定义

官方版 :函数能够访问并记住其词法作用域,即使该函数在父级作用域外执行
人话版:内部函数随身携带出生地(外层函数)的变量,走到哪里都能用


四、闭包的核心原理

1. 词法作用域(出生决定论)

javascript 复制代码
function outer() {
    const phone = "iPhone15"; // 出生时自带的手机
    function inner() {
        console.log(phone); // 永远记得自己出生时有什么
    }
    return inner;
}
  • 函数作用域在定义时确定,和在哪里执行无关
  • 内部函数像婴儿记得母亲(外部函数)的样貌

2. 垃圾回收机制(生存法则)

javascript 复制代码
function outer() {
    const data = "重要资料";
    return function() { 
        console.log(data) 
    };
}

const func = outer(); // 执行完毕
func(); // 仍然能打印"重要资料"
  • JS会自动清除不再使用的变量
  • 闭包会死死抓住用到的变量,不让系统回收

五、闭包实战训练营

案例1:私人保险箱

javascript 复制代码
function createSafe() {
    let money = 0; // 保险箱里的钱,外人无法直接接触

    return {
        deposit: (amount) => {
            money += amount;
            console.log(`存入${amount},余额${money}`);
        },
        checkBalance: () => {
            console.log(`当前余额:${money}`);
        }
    };
}

const mySafe = createSafe();
mySafe.deposit(100); // 存入100,余额100
mySafe.checkBalance(); // 当前余额:100
// 无法直接修改money变量!

闭包部分 :返回的depositcheckBalance方法形成了闭包,锁住了money变量

案例2:网页点击统计

javascript 复制代码
function setupCounter() {
    let count = 0;
    const btn = document.getElementById('myBtn');
    
    btn.addEventListener('click', function() {
        count++;
        console.log(`这是第${count}次点击`);
    });
}
setupCounter();

闭包在哪里 :点击回调函数记住了count变量,即使setupCounter早已执行完毕


六、必知常见问题

Q1:闭包必须return函数吗?

不一定! 只要内部函数逃逸到外部环境,就会形成闭包:

javascript 复制代码
// 情况1:定时器
function startTimer() {
    const startTime = Date.now();
    setInterval(() => {
        console.log(`已运行${Date.now() - startTime}ms`);
    }, 1000);
}

// 情况2:DOM事件
function trackScroll() {
    const scrollY = window.scrollY;
    window.addEventListener('scroll', () => {
        console.log(`当前滚动位置:${scrollY}`);
    });
}

Q2:闭包会导致内存泄漏吗?

不一定!现代浏览器很聪明

只有当闭包长期持有不再需要的大数据时才会泄漏:

javascript 复制代码
// 危险操作!
function leakMemory() {
    const hugeData = new Array(1000000).fill('⚠️'); // 1MB数据
    return function() {
        console.log('这个闭包根本用不到hugeData!');
    };
}

const func = leakMemory(); // hugeData被无意义地保留着

安全操作指南

javascript 复制代码
// 正确做法:及时清理
let usefulClosure = createSafe();
// 使用完毕后...
usefulClosure = null; // 斩断引用链

// 推荐做法:避免保留无用数据
function safeExample() {
    const usefulData = "需要的数据";
    const tempData = "临时数据";
    
    return function() {
        // 只使用usefulData
        console.log(usefulData);
        // tempData在闭包形成后可以清理
        tempData = null; // 手动释放
    };
}

七、闭包使用口诀

  1. 需要长期存数据 → 大胆用闭包
  2. 不再使用的闭包 → 及时设null
  3. 大对象要小心 → 用完就清理
  4. 避免过度使用 → 按需取用

现在你已经是闭包小达人了!试着写个累计计算器练练手吧~ 🚀

遇到问题别担心,多写多调试才是硬道理!

相关推荐
大怪v39 分钟前
前端佬们!塌房了!用过Element-Plus的进来~
前端·javascript·element
拉不动的猪1 小时前
electron的主进程与渲染进程之间的通信
前端·javascript·面试
uhakadotcom1 小时前
零基础玩转千卡训练!Modalities框架中文指南:从安装到实战的全解析
算法·面试·github
uhakadotcom1 小时前
云原生数据仓库对比:Snowflake、Databricks与阿里云MaxCompute
后端·面试·github
fangcaojushi1 小时前
npm常用的命令
前端·npm·node.js
鱼樱前端2 小时前
Rollup 在前端工程化中的核心应用解析-重新认识下Rollup
前端·javascript
uhakadotcom2 小时前
PostgreSQL 行级安全性(RLS)简介
后端·面试·github
rookie fish3 小时前
websocket结合promise的通信协议
javascript·python·websocket·网络协议
PsG喵喵3 小时前
用 Pinia 点燃 Vue 3 应用:状态管理革新之旅
前端·javascript·vue.js
鹏仔工作室3 小时前
vue h5实现车牌号输入框
前端·javascript·vue.js