04.深入闭包和js函数的this指向跟规则

闭包的内存泄漏测试

<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><scriptsrc="./01_js闭包内存泄漏案例.js"></script></html>
functioncreateFnArray(){// 整数占据 4 个字节// arr 占据内存大小:1024 * 1024 * 4 = 4Mvararr=newArray(1024*1024).fill(1)returnfunction(){console.log(arr.length)}}vararrayFns=[]for(vari=0;i<100;i++){setTimeout(()=>{arrayFns.push(createFnArray())},i*100)}setTimeout(()=>{for(vari=0;i<50;i++){setTimeout(()=>{arrayFns.pop()},i*100)}},100*100)

打开浏览器的开发者工具,找到性能模块然后点击录制,我这里录制了40s,由于浏览器的一些干扰因素影响可能不太准确,可自行多录制几次,大致的内存变化就是1-10s 开始慢慢增加内存到 4M,然后 10-15s 过程中数组断开一半的引用,然后由 GC 算法统一回收,内存降到 2M。

闭包引用的自由变量销毁

functionfoo(){varname='why'varage=18// js引擎会将没有使用的变量销毁functionbar(){debuggerconsole.log(name)}returnbar}varfn=foo()fn()

打了 debugger 之后,我们可以在控制台输入 name,以及 age,可以看到 age 是访问报错的

为什么需要 this

在常见的编程语言中,几乎都有 this 这个关键字(Objective-C 中使用的是 self), 但是 JavaScript 中的 this 和常见的面向对象语言中的 this 不太一样

  • 常见面向对象的编程语言中,比如 Java、C++、Swift、Dart 等等一系列语言中,this 通常只会出现在类的方法中
  • 也就是你需要有一个类,类中的方法(特别是实例方法)中,this 代表的是当前调用的对象
  • 但是 JavaScript 中的 this 更加灵活,无论是它出现的位置还是它代表的含义

编写一个 obj 的对象,有 this 和没有 this 的区别

// 从某种角度来说,开发中如果没有 this,很多问题我们也是有解决方案// 但是没有 this,会让我们编写代码变得非常的不方便varobj={name:'why',eating:function(){console.log(this.name+'在吃东西')console.log(obj.name+'在吃东西')// obj 一改动,里面用到 obj 的都要改},running:function(){console.log(this.name+'在跑步')console.log(obj.name+'在跑步')},studying:function(){console.log(this.name+'在学习')console.log(obj.name+'在学习')}}

this 指向什么

在大多数情况下,this 都是出现在函数中

在全局作用域下 this 的指向:

  • 浏览器:window
  • Node 环境:{}

node 环境里面的全局作用域的 this 为什么是{}

在 Node.js 的“全局作用域”里看到的 this 并不是“真正的全局对象”,而是模块作用域里的 this。Node.js 在启动你的文件时,会把文件内容包进一个函数里执行,大致过程:module -> 加载 -> 编译 -> 放到一个函数 -> 执行这个函数.call({}),因此,在“文件顶层”打印 this 得到{},只是 Node 的模块封装机制带来的副作用,而不是浏览器里那种指向全局 window 的行为。

https://registry.npmmirror.com/binary.html?path=node/v14.9.0/

开发中直接在全局作用域下去使用 this,通常都是在函数中使用

  • 所有的函数在被调用时,都会创建一个执行上下文
  • 这个上文中记录着函数的调用栈、AO 对象等
  • this 也是其中的一条记录

this 到底指向什么

下面定义了一个函数,采用三种不同的方式对它进行调用,产生了三种不同的结果

// this 指向什么,跟函数所处的位置没有关系// 跟函数被调用的方式有关系functionfoo(){console.log(this)}// 1. 直接调用这个函数foo()// window// 2. 创建一个对象,对象中的函数指向 foovarobj={name:'why',foo:foo}obj.foo()// obj 对象// 3. 通过 apply 调用foo.apply('abc')// String {'abc'} 对象

这个案例给我们的启示:

  • 函数在调用的时,JavaScript 会默认给这个 this 绑定一个值
  • this 的绑定和定义的位置(编写的位置)没有关系
  • this 的绑定和调用方式以及调用的位置有关系
  • this 是在运行时被绑定的

this 到底是怎么样的绑定规则

绑定规则一:默认绑定

什么情况下使用默认绑定?独立函数调用。

独立的函数调用我们可以理解成函数没有被绑定到某个对象上进行调用。

// 案例1functionfoo(){console.log(this)}foo()// 案例2functionfoo1(){console.log(this)}functionfoo2(){console.log(this)foo1()}functionfoo3(){console.log(this)foo2()}foo3()// 案例3varobj3={name:'why',foo:function(){console.log(this)}}varbar3=obj3.foobar3()// 案例4functionfoo4(){console.log(this)}varobj4={name:'obj4',foo:foo4}varbar4=obj4.foobar4()// 案例5functionfoo5(){functionbar(){console.log(this)}returnbar}varfn=foo5()fn()

绑定规则二:隐式绑定

通过某个对象进行调用的:也就是它的调用位置中,是通过某个对象发起的函数的调用。

隐式绑定有一个前提条件:

  • 必须在调用的对象内部有一个对函数的引用(比如一个属性)
  • 如果没有这样的引用,在进行调用时,会报找不到该函数的错误
  • 正是通过这个引用,间接的将 this 绑定到了这个对象上
// 隐式绑定:object.fn()// object 对象会被 js 引擎绑定到 fn 函数中的 this 里面// 案例1functionfoo(){console.log(this)}varobj={name:'why',foo:foo}obj.foo()// 案例2varobj2={name:'why',eating:function(){console.log(this.name+'在吃东西')},running:function(){console.log(this.name+'在跑步')},studying:function(){console.log(this.name+'在学习')}}obj2.eating()obj2.running()obj2.studying()// 案例3varobj3={name:'obj3',foo:function(){console.log(this)}}varobj4={name:'obj4',bar:obj3.foo}obj4.bar()

绑定规则三:显示绑定

如果我们不希望在对象内部包含这个函数的引用,同时又希望在这个对象上进行强制调用,该怎么做?

  • JavaScript 所有的函数都可以使用 call 和 apply 方法(这个和 Prototype 有关)
  • 这两个函数的第一个参数都要求是一个对象,这个对象的作用是什么?就是给 this 准备的
  • 在调用这个函数时,会将 this 绑定到这个传入的对象上

通过 call 或者 apply 绑定 this 对象,显示绑定后,this 就会明确的指向绑定的对象

functionfoo(){console.log(this)}// foo 直接调用和 call/apply 调用的不同在于 this 绑定的不同// foo 直接调用指向的是全局对象 windowfoo()varobj={name:'why'}// call/apply 是可以指定 this 的绑定对象foo.apply(obj)foo.call(obj)// call/apply 在传参上有所区别functionsum(num1,num2){console.log(num1+num2,this)}sum.apply(obj,[10,20])sum.call(obj,10,20)// call 和 apply 在执行函数时,是可以明确的绑定 this,这个绑定规则称之为显示绑定。

如果希望一个函数总是显示的绑定到一个对象上可以使用 bind

functionfoo(){console.log(this)}// foo.call('kaimo')// foo.call('kaimo')// foo.call('kaimo')// foo.call('kaimo')// foo.call('kaimo')// 默认绑定和显示绑定 bind 冲突:显示绑定优先级更高varnewFoo=foo.bind('kaimo')newFoo()newFoo()newFoo()newFoo()newFoo()

绑定规则四:new 绑定

JavaScript 中的函数可以当做一个类的构造函数来使用,也就是使用 new 关键字

使用 new 关键字来调用函数时,会执行如下的操作:

  • 1.创建一个全新的对象
  • 2.这个新对象会被执行 prototype 链接
  • 3.这个新对象会绑定到函数调用的 this 上(this 的绑定在这个步骤完成)
  • 4.如果函数没有返回其他对象,表达式会返回这个新对象
// 通过一个 new 关键字调用一个函数时(构造器),这个时候 this 是在调用这个构造器时创建出来的对象// this = 创建出来的对象// 这个绑定过程就是 new 绑定functionPerson(name,age){this.name=namethis.age=age console.log(this)}varp1=newPerson('why',18)console.log('p1---->',p1)varp2=newPerson('kaimo',313)console.log('p2---->',p2)

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

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

相关文章

04.深入闭包和js函数的this指向跟规则

闭包的内存泄漏测试 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </…

大模型面试 请分别说说你对 DeepSeek -V3和 DeepSeek -R1的理解,它们在架构或训练策略上有何关键差异?

1.请分别说说你对 DeepSeek -V3和 DeepSeek -R1的理解&#xff0c;它们在架构或训练策略上有何关键差异&#xff1f; 已思考 12s 下面按“我怎么理解它是什么 / 关键技术点 / 与另一者的差异”来分别讲 DeepSeek-V3 和 DeepSeek-R1&#xff0c;并总结它们在架构与训练策略上的…

java BIO、NIO、AIO用法样例

1. BIO (Blocking I/O) - 同步阻塞 I/O BIO 是传统的网络编程模型&#xff0c;每个连接对应一个线程&#xff0c;当线程执行读/写操作时会被阻塞&#xff0c;直到数据就绪。 示例&#xff1a;BIO 服务器 import java.net.*; import java.io.*;public class BioServer {publi…

java垃圾收集 minorgc majargc fullgc

核心概念总览 这三种 GC 类型的本质区别在于回收的堆内存区域和触发原因。GC 类型别名回收区域触发原因特点Minor GCYoung GC只回收年轻代 (Eden Survivor)Eden 区空间不足非常频繁&#xff0c;速度通常很快&#xff0c;使用复制算法Major GCOld GC只回收老年代老年代空间不足…

基于RK3399Pro与RK3568的车载防撞方案:为货车泥头车安全护航

rk3399pro&#xff0c;rk3568&#xff0c;车载方案设计&#xff0c;4路AHD-1080P摄像头输入&#xff0c;防撞识别&#xff0c;助力货车泥头车安全运输&#xff01;在货运行业中&#xff0c;货车与泥头车的安全运输至关重要。今天咱就聊聊基于RK3399Pro和RK3568芯片的车载方案设…

超详细逻辑回归解说

逻辑回归是用来做“分类”的模型&#xff08;比如判断“是不是垃圾邮件”“病人有没有患病”“用户会不会点击广告”&#xff09;&#xff0c;而非回归。它的核心是&#xff1a;用“概率”的方式&#xff0c;把线性回归的输出&#xff08;连续值&#xff09;转化为“是/否”的分…

超声波传感器(HC-SR04)与Arduino Uno及Mixly使用

【结合AI智能体学习记录】一、&#xff08;HC-SR04&#xff09;超声波传感器工作原理&#xff1a;超声波传感器和蝙蝠的定位原理一致&#xff0c;核心是通过计算超声波往返时间来换算距离&#xff1a;1. 触发发射&#xff1a;模块的Trig引脚接收到高电平信号后&#xff0c;会自…

学霸同款2026TOP10AI论文网站:本科生毕业论文神器测评

学霸同款2026TOP10AI论文网站&#xff1a;本科生毕业论文神器测评 2026年学术写作工具测评&#xff1a;为何需要这份榜单&#xff1f; 随着人工智能技术的不断进步&#xff0c;AI论文网站逐渐成为高校学生和研究人员的重要辅助工具。然而&#xff0c;面对市场上琳琅满目的选择&…

react组件内添加一个全局点击时间,点击函数能区分是否是某个特定的id的dom触发的

在 React 组件内添加一个全局点击事件&#xff0c;并判断是否是某个特定 id 的 DOM 触发&#xff0c;可以这样实现&#xff1a; 实现思路 在组件 mount 时&#xff08;useEffect&#xff09;&#xff0c;用 document.addEventListener 注册全局点击事件。回调函数中通过 event.…

.NET 某RFID标签打印客户端 崩溃分析

崩溃分析1. 为什么会崩溃双击打开dump&#xff0c;windbg会自动定位到崩溃的上下文&#xff0c;这一点我比较喜欢&#xff0c;有的时候也省去了用 !analyze -v 无趣的等待&#xff0c;参考输出如下&#xff1a;This dump file has an exception of interest stored in it. The …

游戏打不开、程序闪退怎么办?有效的DLL修复工具推荐,一键拯救你的电脑

“由于找不到MSVCP140.dll&#xff0c;无法继续执行代码。”“应用程序无法正常启动(0xc000007b)。”相信许多电脑用户都遇到过类似的弹窗警告&#xff0c;尤其是在运行新安装的游戏或专业软件时。这些令人头疼的问题&#xff0c;十有八九都指向同一个“元凶”——C运行库的缺失…

风光柴储多目标联合调度问题探索

风光柴储多目标联合调度问题 联合调度分析各部分消纳比例&#xff0c;目标各部分成本最小和排放最小。 约束各部荷电状态&#xff0c;功率平衡等等在当今能源转型的大背景下&#xff0c;风光柴储多目标联合调度成为了热门话题。这种联合调度旨在实现能源的高效利用&#xff0c;…

实体门店新纪元:从“单点AI尝试”到“系统智能体”的转型之路

近两年来&#xff0c;实体经营领域普遍感受到一种“矛盾现象”&#xff1a;技术在不断升级&#xff0c;设备在持续更新&#xff0c;AI话题也频繁出现在各类讨论中&#xff0c;然而&#xff0c;许多门店的经营压力并未因此减轻&#xff0c;反而呈现出更加复杂的挑战。客流获取成…

Oracle 高风险锁等待快速诊断手册

一、手册使用说明1.1 适用场景生产库出现会话阻塞、业务卡顿、事务超时监控工具&#xff08;如OEM、Zabbix&#xff09;告警“锁等待次数突增”“Concurrency等待占比超20%”出现高风险锁事件&#xff08;如enq: CI - contention、enq: TX - allocate ITL entry&#xff09;1.2…

从“经验驱动”到“系统智能”:实体门店经营的结构性升级

当前实体经营领域&#xff0c;普遍存在一个深层挑战&#xff1a;许多门店尽管在工具、设备乃至营销手段上不断更新&#xff0c;但其核心经营逻辑仍停留在较为传统的模式。获客依赖广告与促销&#xff0c;服务依靠人员经验与话术&#xff0c;客户离店后关系难以持续&#xff0c;…

UVM-phase中的object机制

在class uvm_phase extends uvm_object中1. 类的作用和结构这个类是 uvm_phase&#xff0c;它管理测试平台中阶段的 objection 机制。UVM 使用 objection 机制来控制仿真的执行时间&#xff0c;防止测试提前结束。核心成员&#xff1a;systemveriloguvm_objection phase_done; …

AI+IoT双轮驱动:构建风电设备预测性维护数字孪生体的全栈技术实践

凌晨三点&#xff0c;内蒙古某大型风电场运维主管王工接到SCADA系统告警&#xff1a;“#23风机异常停机”。他迅速调取振动频谱图&#xff0c;却发现数据杂乱无章——是主轴承即将失效&#xff1f;还是传感器松动导致误报&#xff1f;抑或只是电网波动引发的瞬时保护动作&#…

UE5 C++(7):

&#xff08;31&#xff09; &#xff08;32&#xff09; 谢谢

企业落地 ChatBI,如何构建可信可靠的数据底座?

在企业 ChatBI 落地过程中&#xff0c;数据底座的技术路线选择直接决定了数据可信度、维护成本和业务响应速度。传统宽表架构在数据口径一致性、维护成本和灵活性上已难以支撑企业级 ChatBI 的规模化应用&#xff0c;而基于 NoETL 明细语义层的方案正成为新一代数据底座的主流选…