精进TypeScript--提供回调中this的类型

JavaScript 的 this 关键字是整个语言中最令人困惑的部分之一。与 let 和 const 声明的变量是具有词法作用域的,与之不同的是,this 是动态作用域:它的值不取决于它怎么定义,而取决于它怎么调用

要记住的事情:

  • 了解 this 绑定的工作原理
  • 当 this 成为你的 API 的一部分时,应该在回调中为它提供一个类型。

this最常用于类中,通常指向对象的当前实例:

class C {vals = [1, 2, 3];logSquares() {for (const val of this.vals) {console.log(val * val);}}
}const c = new C();
c.logSqures(); // 输出 1 4 9

如果你把 logSquares 放在一个变量中并调用它会发生什么:

const c = new C();
const method = c.logSqures();
method(); // ~~ uncaught TypeError: Cannot read property 'vals' of undefined

问题在于,c.logSqures() 实际上做了两件事:调用 C.prototype.logSqures,并且将该函数中 this 的值绑定到 c 上。通过引出一个对 logSquares 的引用,你把两件事分开了,this 被设置为 undefined。

JavaScript 允许你完全控制this的绑定。你可以使用 call 来显式地设置 this 并解决这个问题:

const c = new C();
const method = c.logSqures();
method.call(c);

没有理由让 this 必须绑定到 C 的实例,它可以被绑定到任何东西上。所以,库可以将 this 的值作为其 API 的一部分,甚至 DOM 也利用了这一点。例如,在一个事件处理程序中:

document.querySelector('input').addEventListener('change', function(e) {console.log(this); // 记录事件触发时的输入元素
}

this 绑定经常出现在这样的回调中。例如,如果你想在一个类中定义一个 onClick 处理程序,你可以这样:

class ResetButton {render() {return makeButton({text: 'Reset', onClick: this.onClick});}onclick() {alert(`Reset ${this}`);}
}

当 Button 调用 onClick 时,它会弹出 “Reset undefined”。同样的,问题出在 this 绑定上。一个常见的解决方案是在构造函数中创建方法的绑定:

class ResetButton {constructor() {this.onClick = this.onClick.bind(this);}render() {return makeButton({text: 'Reset', onClick: this.onClick});}onclick() {alert(`Reset ${this}`);}
}

onClick() {…} 在 ResetButton.prototype 上定义了一个属性,这个属性被所以的 ResetButton实例 共享。当你在构造函数中绑定 this.onClick = … 时,它会在 ResetButton 的实例上创建一个名为onClick 的属性,并将 this 绑定到该实例上。在查找序列中,onClick 实例属性排在 onClick 原型属性之前,所以 this.onClick 指的是 render() 方法中已绑定 this 的函数。

绑定有一个快捷方法,使用箭头函数:

class ResetButton {render() {return makeButton({text: 'Reset', onClick: this.onClick});}onclick = () => {alert(`Reset ${this}`); // “this”永远指向 ResetButton 实例}
}

看一下生成的 JavaScript 理解一下:

class ResetButton {constructor() {var _this = this;this.onClick = function() {alert("Reset " + _this);};}render() {return makeButton({text: 'Reset', onClick: this.onClick});}
}

那么这一切和 TypeScript 有什么关系呢?因为 this 绑定是 JavaScript 的一部分,TypeScript 需要对它进行建模。

你可以添加一个this参数到你的回调中:

function addKeyListener(el: HTMLElement,fn: (this: HTMLElement, e: KeyboardEvent) => void
) {el.addEventListener('keydown', e => {fn(el, e); // ~ 期待输入1个参数,但得到2个});
}

更好的是, TypeScript 会强制要求你用正确的 this 上下文来调用函数:

function addKeyListener(el: HTMLElement,fn: (this: HTMLElement, e: KeyboardEvent) => void
) {el.addEventListener('keydown', e => {fn(el); // ~~ 类型为“void” 上下文不可分配给类型为“HTMLElement” 的方法“this”});
}

作为这个函数的使用者,你可以在回调中引用 this,并获得完全的类型安全:

declare let el: HTMLElement;
addKeyListener(el, function(e) {this.innerHTML; // OK,“this”的类型是 HTMLElement
});

当然,如果你在这里使用一个箭头函数,this 就会被覆盖。TypeScript 会捕获这个问题:

class Foo {registerHandler(el: HTMLElement) {addKeyListener(el, e => {this.innerHTML; // ~~ 类型“Foo”上不存在属性“innerHTML”});}
}

不要忘记 this! 如果你在回调中设置 this 的值,那么它就是你的 API 的一部分,就应该在你的类型声明中包含它。

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

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

相关文章

【CSS】浮动笔记及案例

CSS浮动 1. 认识浮动 float属性可以指定一个元素沿着左侧或者是右侧放置,允许文本和内联元素环绕它 float属性最初只使用文字环绕图片但却是早起CSS最好用的左右布局方案 绝对定位、浮动都会让元素脱标,以达到灵活布局的目的可以通过float属性让元素脱…

UE4_材质节点

UE4_材质节点 2017-12-07 13:56 跑九宫格 跑UV 评论(0)

arm裸机-1、定时器pwm

时钟配置 我们使用s3c2440,主频12M,查看用户手册 通过锁相环抬升到400MHZ,分成三条通路,通过HHDIVN和PDIVN配置频率比,这个频率比配置手册已经给出。 配置MPLL主频400Mhz, 通过这个公式算出MPLL s、p、m都…

【XZ-Utils供应链后门漏洞(CVE-2024-3094)】

文章目录 前言 一、事件背景 二、漏洞概述 三、影响范围 四、漏洞检测 五、漏洞防护 前言 近期各个威胁情报中心通报了一例Linux漏洞,在清明节前我们也是进行了自查,幸运的是该漏洞还未集成在发行版中,得以及时发现,没有造…

hive 慢sql 查询

hive 慢sql 查询 查找 hive 执行日志存储路径(一般是 hive-audit.log ) 比如:/var/log/Bigdata/audit/hive/hiveserver/hive-audit.log 解析日志 获取 执行时间 执行 OperationId 执行人 UserNameroot 执行sql 数据分隔符为 \001 并写入 hiv…

滑动窗口(尺取法/Python)

滑动窗口(尺取法) 算法含义: 在解决关于区间特性的题目时保存搜索区间左右端点,然后根据实际要求不断更新左右端点位置的算法 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( 1 ) O(1) O(1) 在历年真题…

C语言——调试技巧

1.Debug和Release的介绍 Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优 的,以便用…

基于单片机的全自动洗衣机系统仿真设计

**单片机设计介绍,基于单片机的全自动洗衣机系统仿真设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的全自动洗衣机系统仿真设计概要是关于利用单片机技术实现全自动洗衣机控制功能的系统设计概述。以…

科东软件参加广州机器人产业联盟举办先进工业母机专家研讨会

工业母机是“制造机器的机器”,具有基础性、通用性、战略性特征,包括了减材切削机床、等材成形装备、增材制造装备及其控制系统等,是衡量国家工业水平和竞争力的重要标志。广东省作为全球知名的制造业基地,非常重视高端装备领域工…

二项队列中删除最大元素C语言实现

在二项队列中删除最大元素通常意味着删除根节点,该节点是队列中所有树中阶最高的树的根。在二项队列中,树的阶是指树中最大的度数加一。删除最大元素后,可能需要重新合并队列中的树以保持二项队列的性质。 以下是一个简单的C语言实现,展示了如何从二项队列中删除最大元素。…

有关字符串算法

例题一 解法: 算法思路(两两⽐较): 我们可以先找出前两个的最⻓公共前缀,然后拿这个最⻓公共前缀依次与后⾯的字符串⽐较,这样就可以找出所有字符串的最⻓公共前缀。 例题二 解法(中⼼扩散&am…

HuggingFace踩坑记录-连不上,根本连不上

学习 transformers 的第一步,往往是几句简单的代码 from transformers import pipelineclassifier pipeline("sentiment-analysis") classifier("We are very happy to show you the 🤗 Transformers library.") ""&quo…

Flask-RESTful 分析

Flask-RESTful 是一个 Flask 扩展,它为构建 RESTful API 提供了方便的工具和资源。它简化了创建 RESTful 服务的过程,允许开发者专注于业务逻辑而不是 HTTP 协议的细节。 资源(Resources): Resource 类:是…

Java集合详解(一)-- List集合

1.集合简介 java集合可分为Set、List、Queue和Map四种体系。 Java集合就像一种容器,可以把多个对象(实际上是对象的引用,但习惯上都称对象)“丢进”该容器中。从Java 5 增加了泛型以后,Java集合可以记住容器中对象的数…

static关键字和const关键字有什么区别

static 关键字和 const 关键字在编程中各自扮演着不同的角色,它们的主要区别体现在以下方面: 作用与用途: static:主要用于修饰变量、方法、代码块和内部类。它确保为特定数据类型或对象分配唯一的存储空间,该空间与创…

PW1503限流芯片:可达3A限流,保障USB电源管理安全高效

在电源管理领域,开关的性能直接关系到设备的稳定性和安全性。今天,我们将详细解析一款备受关注的超低RDS(ON)开关——PW1503。它不仅具有可编程的电流限制功能,还集成了多项保护机制,为各类电子设备提供了高…

解决在统信UOS Linux下缺乏zlib和jpeg库导致的安装Pillow报错问题

☞ ░ 前往老猿Python博客 ░ https://blog.csdn.net/LaoYuanPython 一、引言 今天在统信UOS Linux的Python3环境下安装Pillow遇到了问题,导致安装不成功,通过报错信息。 二、第一执行pip3 install pillow安装报错 为了提高效率,指向了清华…

Windows下如何确定虚函数在虚函数表中的位置

我需要用c#调用 c 的 类的函数, 虽然可以通过头文件的顺序,但是如果可以打印出虚函数在虚表中的Offset更好。 测试要求: Windows, x86 只有1层虚函数,没有被override过 虚函数调用如下 auto a_reqCreditDetail &XtTraderApi::reqCreditDetail; (a…

论STM32如何使用I2C协议

前言 当提到STM32微控制器使用I2C协议时,通常意味着通过I2C总线与其他外设进行通信。I2C(Inter-Integrated Circuit)是一种常用的串行通信协议,用于在微控制器和外部设备之间传输数据。ST公司的STM32系列微控制器广泛应用于各种嵌…

Spring重点知识(个人整理笔记)

目录 1. 为什么要使用 spring? 2. 解释一下什么是 Aop? 3. AOP有哪些实现方式? 4. Spring AOP的实现原理 5. JDK动态代理和CGLIB动态代理的区别? 6. 解释一下什么是 ioc? 7. spring 有哪些主要模块?…