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

JS中的闭包详解

文章目录

  • JS中的闭包详解
    • 一、引言
    • 二、闭包的基本概念
      • 1、闭包的定义
        • 1.1、代码示例
      • 2、闭包的实现
        • 1.2、代码示例
    • 三、闭包的用途
      • 1、封装私有变量
        • 1.3、代码示例
      • 2、做缓存
        • 1.4、代码示例
      • 3、模块化编程
        • 1.5、代码示例
      • 4、防抖、节流、函数柯里化
        • 1.6、防抖代码示例
        • 1.7、节流代码示例
    • 四、闭包的缺点
    • 五、总结

JS中的闭包详解

一、引言

闭包是JavaScript中的一个核心概念,它允许函数访问其定义时的词法作用域中的变量。这种特性使得闭包在数据封装、回调函数、模块模式等场景中有着广泛的应用。
在这里插入图片描述

二、闭包的基本概念

1、闭包的定义

闭包是指有权访问另一个函数作用域的变量的函数。在JavaScript中,闭包可以通过函数嵌套和变量引用实现。

1.1、代码示例
function outerFun() {
    let outerVar = '我在outer函数里!';
    function innerFun() {
        console.log(outerVar);
    }
    return innerFun;
}
const innerFn = outerFun();
innerFn(); // 输出: 我在outer函数里!

在这个例子中,innerFun引用了outerVar,因此JavaScript引擎会保留outerFun的作用域链,以便innerFun可以访问outerVar

2、闭包的实现

闭包是指一个函数可以访问它定义时所在的词法作用域以及全局作用域中的变量。当内部函数引用外部函数的变量时,外部函数的作用域链将被保留在内存中,以便内部函数可以访问这些变量。

1.2、代码示例
function a() {
    var aa = 333;
    function b() {
        console.log(aa); // 输出:333
    }
    return b;
}
var demo = a();
demo(); // 输出:333

在这个例子中,b函数引用了a函数中的变量aa,因此即使a函数执行完毕后,aa变量仍然可以通过b函数被访问,形成了闭包。

三、闭包的用途

1、封装私有变量

闭包可以用于封装私有变量,以防止其被外部访问和修改。这可以减少全局变量的数量,降低全局变量被误用或意外修改的风险。

1.3、代码示例
function addFn() {
    let count = 1;
    function increment() {
        count++;
        console.log(count);
    }
    return increment;
}
const counter = addFn();
counter(); // 输出:2
counter(); // 输出:3

在这个例子中,increment函数通过闭包访问并修改了count变量,而count变量不会被外部直接访问。

2、做缓存

闭包可以用于缓存计算结果,减少重复计算。

1.4、代码示例
function fn1() {
    var type = 'JavaScript';
    let tt1 = 1;
    const tt2 = 2;
    var innerBar = {
        getType: function() {
            console.log(tt1);
            return type;
        },
        setType: function(newType) {
            type = newType;
        }
    };
    return innerBar;
}
var bar = fn1();
console.log(bar.getType()); // 输出:1 JavaScript
bar.setType('Python');
console.log(bar.getType()); // 输出:1 Python

在这个例子中,getTypesetType方法通过闭包访问并修改了type变量。

3、模块化编程

闭包可以用于实现模块化编程,封装模块的私有变量和方法。

1.5、代码示例
const moduleFn = (function() {
    let privateVar = '我是私有变量!';
    function privateMethod() {
        console.log(privateVar);
    }
    return {
        publicMethod: function() {
            privateMethod();
        }
    };
})();
moduleFn.publicMethod(); // 输出:我是私有的!

在这个例子中,privateVarprivateMethod被封装在模块内部,只能通过publicMethod访问。

4、防抖、节流、函数柯里化

闭包在实现防抖、节流和函数柯里化等高级功能时非常有用。

1.6、防抖代码示例
function antishake(fn, wait) {
    let timer = null;
    return function() {
        clearTimeout(timer);
        timer = setTimeout(() => {
            fn();
        }, wait);
    };
}
let an = antishake(function() {
    console.log('555');
}, 2000);
document.querySelector('div').onmouseenter = () => {
    an();
};
1.7、节流代码示例
function throttle(fn, wait) {
    let timer = null;
    return function() {
        if (timer) return;
        timer = setTimeout(() => {
            fn();
            timer = null;
        }, wait);
    };
}
let throttle1 = throttle(() => {
    console.log('我上车了');
}, 2000);
document.querySelector('div').onclick = () => {
    throttle1();
};

四、闭包的缺点

闭包可能会导致内存泄漏,因为闭包引用的外部变量不会被垃圾回收。为了避免内存泄漏,可以及时释放闭包或者使用立即执行函数。

五、总结

闭包是JavaScript中一个强大的特性,它允许函数访问其创建时的词法作用域。通过闭包,可以实现数据封装、事件处理、延迟执行等多种高级功能。理解闭包的概念和工作原理对于深入掌握JavaScript至关重要。


版权声明:本博客内容为原创,转载请保留原文链接及作者信息。

参考文章

  • 什么是闭包?以及闭包的作用—JavaScript基础篇 - CSDN博客

http://www.kler.cn/a/443147.html

相关文章:

  • MySQL学习笔记2【函数/约束/多表查询】
  • 【css】浏览器强制设置元素状态(hover|focus……)
  • Nacos server 2.4.0 版本已知问题和 Bug 汇总
  • 鼠标自动移动防止锁屏的办公神器 —— 定时执行专家
  • 科大讯飞前端面试题及参考答案 (下)
  • uniapp 微信小程序内嵌h5实时通信
  • 搭建分布式ZooKeeper集群
  • 音频开发中常见的知识体系
  • clickhouse-数据库引擎
  • Web APIs - 第5章笔记
  • 海量数据-Vastbase G100数据库安装
  • PHP源码加密之php-beast
  • sqoop导入hdfs,hive
  • Linux查看是否有www-data用户,如果没有添加一个
  • 算法-Z-order算法
  • form表单校验对象中的对象的属性 / 根据表单中某一个数据动态添加其他项是否必填
  • 软件测试丨性能测试基本概念
  • CAD学习 day3
  • MySQL系列之数据类型(String)
  • qt-C++笔记之继承自 QWidget和继承自QObject 并通过 getWidget() 显示窗口或控件时的区别和原理
  • 绿色浪潮,VELO Angel Glide坐垫奏响环保骑行乐章
  • VUE3 笔记总结
  • abc 384 D(子数组->前缀和) +E(bfs 扩展的时候 按照数值去扩展)
  • 【中工开发者】HarmonyOS APP打怪小游戏
  • QMainwindow的鼠标跟踪事件不触发问题
  • C/C++ 匿名namespace和有名namespace的区别