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

相关推荐
Revolution611 小时前
一段 JavaScript 代码执行时,到底发生了什么
前端·javascript
To_OC10 小时前
LC 131 分割回文串:刚学回溯时,我连怎么切字符串都想不明白
javascript·算法·leetcode
To_OC12 小时前
LC 42 接雨水:暴力超时卡半天?前后缀数组一用就通了
javascript·算法·leetcode
小林ixn12 小时前
从 ??= 到 onKeyDown:一个 React 组件的“自我修养”
前端·javascript·react.js
এ慕ོ冬℘゜13 小时前
前端实战:jQuery 多条件联合搜索(标题模糊查询 + 日历时间段筛选)
前端·javascript·jquery
随心点儿13 小时前
js postMessage 实现跨域发送消息-应用示例
javascript·ecmascript·postmessage
kyriewen15 小时前
我让AI改一个bug——它偷偷动了5个我没让它碰的地方
前端·javascript·ai编程
gis开发之家19 小时前
《Vue3 从入门到大神35篇》Vue3 源码详解(五):effect 依赖收集原理——track 与 trigger 是如何工作的?
javascript·typescript·前端框架·vue3·vue3源码
橘子星20 小时前
我一个前端切图仔,凭什么能在浏览器里跑大模型?
前端·javascript·前端框架
半个落月20 小时前
用 LangChain JS 做可控写作实验:理解温度参数、提示词与异步调用
javascript·人工智能·后端