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

JS—闭包:3分钟从入门到放弃

个人博客:haichenyi.com。感谢关注

一. 目录

  • 一–目录
  • 二–基础定义
  • 三–闭包的运行机制
  • 四–闭包实战应用场景
  • 五–内存泄漏预防指南
  • 六–最佳实践总结

二. 基础定义

  闭包:能够访问外部函数作用域的函数,以及其词法环境的组合。举个老生常谈栗子:

function createCounter() {
    let count = 0; // 被闭包捕获的变量
    
    return function() {//内部大括号
        count += 1;
        return count;
    };
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2

  解析一下上面这段代码:

  1. 上面这个例子,有两个方法,一个是外部的createCounter方法,一个是内部的return 的方法。
  2. 外部createCounter方法定义了一个变量count
  3. 内部return的方法,使用了这个变量,让这个变量+1,然后返回。
  4. 我们都知道内部可以访问外部变量,这是没有问题的。反过来,外部不能访问内部变量(var除外)
      我们再来说这个概念。
    a. 访问外部函数作用域的函数,指的就是上面例子中的return返回的函数
    b. 词法环境,简单的理解就是作用域,也就是两个大括号之间的东西(不够严谨,可以简单的这么理解)

三. 闭包的运行机制

3.1 词法作用域链

function outer() {
    const x = 10;
    
    function inner() {
        console.log(x); // 访问父作用域的x
    }
    
    return inner;
}
  • 函数定义时确定作用域链
  • 闭包在outer执行结束后依然保留对x的访问

3.2 内存模型解析

function createClosure() {
    const bigData = new Array(1000000); // 大数据
    
    return () => console.log(bigData.length);
}

const closure = createClosure();
  • 闭包持有对父作用域整个变量对象的引用
  • 错误的闭包使用会导致bigData无法被GC回收

四. 闭包实战应用场景

4.1 模块模式(现代ES6替代方案export,import)

const calculator = (() => {
    let memory = 0;
    
    return {
        add: (x) => memory += x,
        reset: () => memory = 0
    };
})();

calculator.add(5); // 5
calculator.reset();

对标ES6的export,import

//tool.js
let memory = 0
export function add(x) {
	return memory +x
}
export function reset() {
	memory =0
}
//在需要用的位置import tool.js文件的add和reset两个方法即可

五. 内存泄漏预防指南

5.1 常见泄漏场景

  • DOM元素引用
function createClosure() {
    const element = document.getElementById('bigElement');
    
    return () => {
        console.log(element.offsetWidth);
    };
}
  • 未清理的定时器
function startTimer() {
    const data = fetchData();
    
    setInterval(() => {
        process(data); // data被长期持有
    }, 1000);
}

5.2 优化策略

  • ​解除引用:在不再需要时手动置null
function cleanClosure() {
    let data = /* ... */;
    
    const cleanup = () => {
        data = null;
    };
    
    return { processData, cleanup };
}
  • 使用WeakMap/WeakRef
const weakCache = new WeakMap();

function cacheData(element, data) {
   weakCache.set(element, data);
}
  • ​事件监听器管理
function setupListeners() {
   const handler = () => {/* ... */};
   
   element.addEventListener('click', handler);
   
   return () => {
       element.removeEventListener('click', handler);
   };
}

六. 最佳实践总结

  1. ​最小化闭包作用域
    • 只保留必要的变量
    • 及时解除无用引用
  2. 优先使用块级作用域
//在类似于这种循环时,使用let,const,不要使用var
for (let i = 0; i < 10; i++) {
    setTimeout(() => console.log(i), 100);
}
  1. 模块化代码结构
// ES Modules
export const createClosure = () => { /* ... */ };
//也就是使用ES6的export 和 import
  1. 配合垃圾回收机制:避免循环引用;使用WeakMap代替普通对象

相关文章:

  • OpenAI Agent 工具包深度解析:重塑 AI 代理开发的未来图景
  • 2025/03/12(嵌入式学习开始第六天)<刷题>
  • Windows 图形显示驱动开发-WDDM 3.2- WDDM 功能的内核模式测试
  • docker安装和卸载
  • AGI大模型(4):编程调用 OpenAI API
  • 计算机组成原理之基本元器件和逻辑门构成
  • 从学习ts的三斜线指令到项目中声明类型的最佳实践
  • CSP模拟考试系统共享
  • Web网页制作之爱家居的设计(静态网页)
  • 辨析Corollary、Theorem和lemma
  • unet模型在车道线检测上的应用【代码+数据集+python环境+GUI系统】
  • 当输入没有注册的用户名和密码,直接跳转到了一个404页面是怎么回事
  • 判断能否形成等差数列 - 简单
  • P9241 [蓝桥杯 2023 省 B] 飞机降落
  • 第44天:WEB攻防-PHP应用SQL盲注布尔回显延时判断报错处理增删改查方式
  • SpaceSync智能排班:重构未来办公空间的神经中枢
  • AI对前端开发的冲击
  • msf(Metasploit)中Session与Channel的区别与关系解析
  • 微信小程序项目 tabBar 配置问题:“pages/mine/mine“ need in [“pages“]
  • 计算机硬件与体系结构
  • 聚焦智能浪潮下的创业突围,“青年草坪创新创业湃对”走进北杨人工智能小镇
  • 淄博一酒店房间内被曝发现摄像头,当地警方已立案调查
  • 舱位已排到月底,跨境电商忙补货!美线订单大增面临爆舱,6月运价或翻倍
  • 共建医学人工智能高地,上海卫健委与徐汇区将在这些方面合作
  • 泽连斯基抵达安卡拉,称乌将派出最高级别代表团参与谈判
  • 病重老人被要求亲自取钱在农业银行门口去世?株洲警方介入