深入探讨防抖函数中的 this 上下文

深入剖析防抖函数中的 this 上下文

最近我在研究防抖函数实现的时候,发现一个耗费脑子的问题,出现了令我困惑的问题。接下来,我将通过代码示例,深入探究这些现象背后的原理。

示例代码

function debounce(fn, delay) {let timer = null;console.log(1, 'this:', this);return function(...args) {console.log(2, 'this:', this);if (timer) clearTimeout(timer);timer = setTimeout(() => {console.log(3, 'this:', this);  fn.apply(this, args);}, delay);};
}function debounce2(fn, delay) {  let timer = null;console.log(11, 'this:', this);return function(...args) {  console.log(22, 'this:', this);if (timer) clearTimeout(timer);timer = setTimeout(function() {console.log(33, 'this:', this);fn.apply(this, args);}, delay);};
}let obj = {name: 'John',sayName: function() {console.log(this.name);},debouncedSayName: debounce(function() {this.sayName();}, 300),debouncedSayName2: debounce2(function() {this.sayName();}, 300)
};obj.debouncedSayName();
obj.debouncedSayName2();

现象与问题

运行上述代码后(假设在浏览器环境中),会得到如下输出:
在这里插入图片描述

这里有一个顺序问题让我困惑了一下:

  1. 顺序问题:为什么 1 打印完成后没有紧接着打印 2,而是先打印了 11 ?并且为什么输出顺序不是 2 -> 3 -> 22 -> 33 呢?

为了彻底搞清楚这些现象,下面是对知识点的解析。

关键知识点解析

1. 函数定义时的 this(打印 111 处)

debouncedebounce2 函数的定义里,console.log(1, 'this:', this)console.log(11, 'this:', this) 中的 this 指向取决于函数的调用方式。由于这两个函数是直接定义在全局作用域下的,并没有通过某个对象来调用,所以在 JavaScript 中,this 默认指向全局对象 Window(在 Node.js 环境中则是 global)。

2. 内部返回函数中的 this(打印 222 处)

return 的匿名函数中,console.log(2, 'this:', this)console.log(22, 'this:', this) 里的 this 指向是由调用时的上下文决定的。
当我们执行 obj.debouncedSayName()obj.debouncedSayName2() 时,这两个函数是作为 obj 对象的方法被调用的。根据 JavaScript 的规则,当函数作为对象的方法调用时,this 会指向调用该方法的对象,所以这两个地方的 this 都指向 obj

3. 定时器中的 this(打印 333 处)

  • 箭头函数中的 thisconsole.log(3, 'this:', this):在 debounce 函数的定时器回调中使用了箭头函数。箭头函数有一个重要的特性,就是它不会绑定自己的 this,而是继承自定义它的外部函数(这里是匿名函数)的 this。因此,这里的 this 仍然指向 obj
  • 普通函数中的 thisconsole.log(33, 'this:', this):在 debounce2 函数的定时器回调中使用的是普通函数。普通函数的 this 在调用时会动态绑定,而在定时器中,普通函数的 this 默认指向全局对象 Window(在 Node.js 环境中是 timeout)。

顺序问题解析

观察输出顺序:1 -> 11 -> 2 -> 22 -> 3 -> 33

为什么不是 1 -> 2

当我们定义 obj 对象时,会通过 debouncedebounce2 函数生成 debouncedSayNamedebouncedSayName2 属性。在这个过程中,debouncedebounce2 函数会被调用,于是就会执行到 console.log(1, 'this:', this)console.log(11, 'this:', this)。而 debouncedebounce2 返回的内部函数,要等到调用 obj.debouncedSayName()obj.debouncedSayName2() 时才会执行。

为什么不是 2 -> 3 -> 22 -> 33

JavaScript 是单线程的编程语言,而 setTimeout 是异步操作。当遇到 setTimeout 时,它会将回调函数推入事件队列,等待主线程的同步任务全部执行完毕后再执行。因此,debouncedSayNamedebouncedSayName2 的同步部分会先执行,分别打印 222,然后才会将定时器的回调函数放入事件队列。最后,定时器的回调函数依次执行,分别打印 333

总结

通过这个例子,我们可以得出以下重要结论:

1. 箭头函数与普通函数的区别

  • 箭头函数:箭头函数中的 this 继承自外层函数,这使得它非常适合用于需要保留上下文的场景。
  • 普通函数:普通函数的 this 根据调用方式动态绑定,在不同的调用场景下,this 的指向可能会发生变化。

2. 异步任务的执行顺序

异步任务会被推入事件队列,只有当主线程的同步任务全部完成后,才会依次执行事件队列中的异步任务。

3. this 的指向受调用方式影响

如果函数作为对象的方法调用,this 会指向该对象;如果函数没有通过对象调用,this 通常指向全局对象(在严格模式下为 undefined)。

希望通过这篇文章,你能更清晰地理解防抖函数中的 this 机制,在实际开发中避免因 this 指向问题而产生的错误。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/8791.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

进程通讯——类型和发展

进程常用交互方法如上

健康AI应用的逆袭:如何用“死亡时钟”撬动用户增长和媒体关注,实现应用榜快速排名第六

Death Clock:一款AI驱动的长寿应用 过去六个月里,我一直在为一款名为 Death Clock 的AI驱动长寿应用提供建议。健康类应用的增长向来十分困难,因为它们通常是单人使用的工具,且主要吸引年长的用户群体。然而,与创始人…

区块链在能源行业的应用场景

区块链技术在能源行业的应用正在逐步扩展,并且展现出巨大的潜力。它不仅能够促进能源交易的透明度和效率,还能为能源生产、分配、消费等多个环节提供创新解决方案。以下是对区块链在能源行业应用的一些深入探讨: 1. 能源交易 区块链可以实现…

论文阅读(十五):DNA甲基化水平分析的潜变量模型

1.论文链接:Latent Variable Models for Analyzing DNA Methylation 摘要: 脱氧核糖核酸(DNA)甲基化与细胞分化密切相关。例如,已经观察到肿瘤细胞中的DNA甲基化编码关于肿瘤的表型信息。因此,通过研究DNA…

基于PostgreSQL的自然语义解析电子病历编程实践与探索(上)

一、引言 1.1研究目标与内容 本研究旨在构建一个基于 PostgreSQL 的自然语义解析电子病历编程体系,实现从电子病历文本中提取结构化信息,并将其存储于 PostgreSQL 数据库中,以支持高效的查询和分析。具体研究内容包括: 电子病历的预处理与自然语言处理:对电子病历文本进…

第1章 量子暗网中的血色黎明

月球暗面的危机与阴谋 量子隧穿效应催生的幽蓝电弧,于环形山表面肆意跳跃,仿若无数奋力挣扎的机械蠕虫,将月球暗面的死寂打破,徒增几分诡异。艾丽伫立在被遗弃的“广寒宫”量子基站顶端,机械义眼之中,倒映着…

【落羽的落羽 数据结构篇】顺序表

文章目录 一、线性表二、顺序表1. 概念与分类2. 准备工作3. 静态顺序表4. 动态顺序表4.1 定义顺序表结构4.2 顺序表的初始化4.3 检查空间是否足够4.3 尾部插入数据4.4 头部插入数据4.5 尾部删除数据4.6 头部删除数据4.7 在指定位置插入数据4.8 在指定位置删除数据4.9 顺序表的销…

大模型GUI系列论文阅读 DAY4续:《Large Language Model Agent for Fake News Detection》

摘要 在当前的数字时代,在线平台上虚假信息的迅速传播对社会福祉、公众信任和民主进程构成了重大挑战,并影响着关键决策和公众舆论。为应对这些挑战,自动化假新闻检测机制的需求日益增长。 预训练的大型语言模型(LLMs&#xff0…

基于物联网的智能环境监测系统(论文+源码)

1系统的功能及方案设计 本课题为基于物联网的智能环境监测系统的设计与实现,整个系统采用stm32f103单片机作为主控制器,通过DHT11传感器实现智能环境监测系统温度和湿度的检测,通过MQ传感器实现CO2浓度检测,通过光照传感器实现光照…

反向代理模块。。

1 概念 1.1 反向代理概念 反向代理是指以代理服务器来接收客户端的请求,然后将请求转发给内部网络上的服务器,将从服务器上得到的结果返回给客户端,此时代理服务器对外表现为一个反向代理服务器。 对于客户端来说,反向代理就相当于…

AI工具灵感速递:离线ChatGPT×自然语言全栈开发×智能文件重命名,开发者效率革命!

↓ 关注小前,捕获全球产品灵感 ↓ ⚡️ 1句Slogan榨干产品灵魂 ⚡️ 3秒 get 全球独立开发者的爆款灵感 今日精选速览: ▸ Llamao:离线私密ChatGPT,设备端AI助手 ▸ co.dev:用自然语言打造全栈应用 ▸ Smart Bul…

【MySQL — 数据库增删改查操作】深入解析MySQL的 Update 和 Delete 操作

1. 测试数据 mysql> select* from exam1; ----------------------------------------- | id | name | Chinese | Math | English | ----------------------------------------- | 1 | 唐三藏 | 67.0 | 98.0 | 56.0 | | 2 | 孙悟空 | 87.0 | 78.…

fpga系列 HDL:XILINX Vivado Vitis 高层次综合(HLS) 实现 EBAZ板LED控制(上)

目录 创建工程创建源文件并编写C代码C仿真综合仿真导出RTL CG导出RTL错误处理: 创建工程 创建源文件并编写C代码 创建源文件(Souces下的hlsv.h和hlsv.cpp,Test Bench下的test_hlsv1.cpp): hlsv1.h #ifndef HLSV1 #define HLSV1 #include &l…

定西市建筑房屋轮廓数据shp格式gis无偏移坐标(字段有高度和楼层)内容测评

定西市建筑房屋轮廓数据是GIS(Geographic Information System,地理信息系统)领域的重要资源,用于城市规划、土地管理、环境保护等多个方面。这份2022年的数据集采用shp(Shapefile)格式,这是一种…

学习数据结构(1)时间复杂度

1.数据结构和算法 (1)数据结构是计算机存储、组织数据的方式,指相互之间存在⼀种或多种特定关系的数据元素的集合 (2)算法就是定义良好的计算过程,取一个或一组的值为输入,并产生出一个或一组…

有限元分析学习——Anasys Workbanch第一阶段笔记梳理

第一阶段笔记主要源自于哔哩哔哩《ANSYS-workbench 有限元分析应用基础教程》 张晔 主要内容导图: 笔记导航如下: Anasys Workbanch第一阶段笔记(1)基本信息与结果解读_有限元分析变形比例-CSDN博客 Anasys Workbanch第一阶段笔记(2)网格单元与应力奇…

设计模式Python版 原型模式

文章目录 前言一、原型模式二、原型模式示例三、原型管理器 前言 GOF设计模式分三大类: 创建型模式:关注对象的创建过程,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。结构型模式:关注类和对…

【Redis】缓存+分布式锁

目录 缓存 Redis最主要的使用场景就是作为缓存 缓存的更新策略: 1.定期生成 2.实时生成 面试重点: 缓存预热(Cache preheating): 缓存穿透(Cache penetration) 缓存雪崩 (Cache avalan…

小阿卡纳牌

小阿卡纳牌 风:热湿 火:热干 水:冷湿 土:冷干 火风:温度相同,但是湿度不同,二人可能会在短期内十分热情,但是等待热情消退之后,会趋于平淡。 湿度相同、温度不同&#x…

初始JavaEE篇 —— Spring Web MVC入门(上)

找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程程(ಥ_ಥ)-CSDN博客 所属专栏:JavaEE 目录 RequestMappingg 注解介绍 Postman的介绍与使用 PostMapping 与 GetMapping 注解 构造并接收请求 接收简单参数 接收对象…