js面试题每日一题:什么是闭包?

一、闭包的核心定义

闭包是指函数与其引用的外部变量的绑定组合。具体来说,当内部函数被保存到外部时,会形成闭包 ------ 内部函数可访问外部函数的变量和作用域,即使外部函数已执行完毕,这些变量也不会被垃圾回收机制销毁。

二、闭包的三大关键特征

  1. 作用域嵌套:外部函数包含内部函数,内部函数引用外部函数的变量。
  2. 返回内部函数:外部函数返回内部函数,使内部函数能在外部被调用。
  3. 变量持久化:外部函数执行结束后,其变量因被内部函数引用而保留在内存中。

三、闭包的典型体现形式

  1. 函数嵌套返回

    javascript

    javascript 复制代码
    function outer() {
      const count = 0; // 外部函数变量
      function inner() {
        return count++; // 内部函数引用外部变量
      }
      return inner; // 返回内部函数
    }
    
    const counter = outer(); // 调用外部函数,获取内部函数
    console.log(counter()); // 输出 0
    console.log(counter()); // 输出 1
  2. 立即执行函数(IIFE)

    javascript

    javascript 复制代码
    const add = (function() {
      let sum = 0; // IIFE作用域内的变量
      return function(num) {
        sum += num;
        return sum;
      };
    })();
    
    console.log(add(5)); // 输出 5
    console.log(add(3)); // 输出 8

四、闭包的核心作用:保护变量与封装数据

  • 隔离变量,避免全局污染:闭包中的变量仅能通过内部函数访问,防止被全局作用域篡改。

    javascript

    javascript 复制代码
    // 示例:封装计数器,避免全局变量污染
    function createCounter() {
      let count = 0;
      return {
        increment() { return ++count; },
        decrement() { return --count; }
      };
    }
    
    const counter = createCounter();
    console.log(counter.increment()); // 1
    console.log(counter.decrement()); // 0
    // 无法直接访问count变量,避免外部篡改
  • 实现 "私有属性" 效果:在 ES6 类语法出现前,闭包是模拟私有变量的主要方式。

五、闭包解决的经典问题

  1. 循环中绑定事件的变量作用域问题

    javascript

    javascript 复制代码
    // 错误示例:普通循环中点击事件获取的i都是最终值
    for (var i = 0; i < 5; i++) {
      document.getElementById(`btn${i}`).onclick = function() {
        console.log(i); // 输出5(所有按钮都一样)
      };
    }
    
    // 闭包解决方案:用IIFE保存每次循环的i值
    for (var i = 0; i < 5; i++) {
      (function(j) {
        document.getElementById(`btn${j}`).onclick = function() {
          console.log(j); // 正确输出0-4
        };
      })(i);
    }
  2. 循环中定时器的变量取值问题

    javascript

    javascript 复制代码
    // 闭包确保定时器获取正确的循环变量
    for (var i = 0; i < 3; i++) {
      (function(j) {
        setTimeout(() => {
          console.log(j); // 依次输出0,1,2
        }, j * 1000);
      })(i);
    }

六、闭包的缺陷:内存泄漏风险

  • 问题本质:闭包会保留外部函数的变量,若大量使用且未正确释放,可能导致内存占用过高。

  • 典型场景

    1. 长时间持有大型数据的闭包(如缓存函数返回的大数据对象)。
    2. 未清理的事件监听闭包(如组件卸载时未移除的 DOM 事件)。
  • 解决方案

    • 避免不必要的闭包嵌套;
    • 组件卸载时清除闭包引用(如清除定时器、解绑事件)。

七、闭包的内存机制:栈与堆的协同

  • 基本数据类型(栈内存) :存储在栈中,按 "先进后出" 规则管理(如闭包中的数字、字符串)。
  • 引用数据类型(堆内存) :存储在堆中,按引用关系管理,闭包会通过引用保持堆内存中的对象不被释放(如对象、数组)。

总结

闭包是 JavaScript 函数式编程的核心特性,通过 "作用域嵌套 + 变量持久化" 实现数据封装与隐私保护,但需注意内存管理。理解闭包不仅是面试高频考点,更是掌握前端性能优化和复杂逻辑实现的基础。

相关推荐
保持学习ing2 小时前
帝可得 - 设备管理
javascript·vue.js·elementui
烛阴3 小时前
自动化测试、前后端mock数据量产利器:Chance.js深度教程
前端·javascript·后端
每天都有好果汁吃3 小时前
基于 react-use 的 useIdle:业务场景下的用户空闲检测解决方案
前端·javascript·react.js
占星安啦4 小时前
一个html实现数据库自定义查询
java·前端·javascript·数据库·动态查询
老K(郭云开)5 小时前
allWebPlugin中间件VLC专用版之截图功能介绍
前端·javascript·chrome·中间件·edge
Rousson5 小时前
硬件学习笔记--65 MCU的RAM及FLash简介
开发语言·前端·javascript
萌萌哒草头将军5 小时前
🏖️ TanStack Router:搜索参数即状态!🚀🚀🚀
javascript·vue.js·react.js
小疯仔7 小时前
使用el-input数字校验,输入汉字之后校验取消不掉
android·开发语言·javascript
wangbing11257 小时前
开发指南120-表格(el-table)斑马纹
javascript·vue.js·elementui
Joe5567 小时前
antDesignVue中a-upload上传组件的使用
前端·javascript