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

TypeScript 函数

函数是JavaScript应用程序的基础。 它帮助你实现抽象层,模拟类,信息隐藏和模块。 在TypeScript里,虽然已经支持类,命名空间和模块,但函数仍然是主要的定义 行为 的地方。 TypeScript为JavaScript函数添加了额外的功能,让我们可以更容易地使用。

在 TypeScript 中,函数是用于执行特定任务并可能返回结果的代码块。

函数类型

可以为函数定义类型来明确函数的参数类型和返回值类型。

// 有名字的函数
function sum(a: number, b: number): number {return a + b;
}
// 匿名函数
let mySum = function(x: number, y: number): number { return x + y; };

这里明确了 sum 函数接受两个 number 类型的参数 ab,并返回一个 number 类型的值。

书写完整函数类型

函数类型包含两部分:参数类型和返回值类型。 当写出完整函数类型的时候,这两部分都是需要的。

在函数和返回值类型之前使用( =>)符号。

返回值类型是函数类型的必要部分,如果函数没有返回任何值,必须指定返回值类型为 void 而不能留空。

let mySum: (x: number, y: number) => number =function(x: number, y: number): number { return x + y; };

在这段代码中:

  • let mySum: (x: number, y: number) => number 这部分定义了一个变量 mySum,并指定了它的类型为接受两个 number 类型参数并返回 number 类型值的函数类型。
  • 然后通过 function(x: number, y: number): number { return x + y; }mySum 变量赋值了一个具体的函数实现。

以参数列表的形式写出参数类型,为每个参数指定一个名字和类型:

let mySum: (a: number, b: number) => number =function(x: number, y: number): number { return x + y; };

在这段代码中,虽然函数定义中的参数名 ab 与函数实现中的参数名 xy 不同,但它们的类型都是 number,这是匹配的。

TypeScript 在类型检查时关注的是参数的类型,而不是参数的名称。只要参数的类型符合函数类型定义的要求,代码就可以通过类型检查。

在定义函数的类型时,只考虑参数的类型和返回值的类型。

函数中使用的捕获变量不会体现在类型里。 实际上,这些变量是函数的隐藏状态并不是组成API的一部分。
这是因为这些捕获变量属于函数的内部实现细节,对于使用该函数的外部代码来说,并不需要知道这些内部的状态。函数的 API 主要是通过其公开的参数和返回值来与外部进行交互和通信。
示例:

let outerValue = 10;function myFunction(x: number): number {let innerValue = 5;return x + outerValue + innerValue;
}

在上述 myFunction 函数中,outerValue 是捕获的外部变量,innerValue 是函数内部的变量,它们都不会体现在函数的类型 (x: number) => number 中。

推断类型

如果在赋值语句的一边指定了类型,但是另一边没有类型的话,TypeScript编译器会自动识别出类型:

let mySum = function(x: number, y: number): number { return x + y; };

在这个例子中,mySum 的类型会被推断为 (x: number, y: number) => number
在这里插入图片描述

可选参数和默认参数

JavaScript里,每个参数都是可选的,可传可不传。 没传参的时候,它的值就是undefined

TypeScript里的每个函数参数都是必须的。传递给一个函数的参数个数必须与函数期望的参数个数一致。

在 TypeScript 中,可选参数和默认参数为函数提供了更灵活的参数设置方式。

可选参数

通过在参数名后面添加 ? 来标记参数为可选参数。调用函数时,可以选择不传递该参数。
示例:

function printInfo(name: string, age?: number) {console.log(`Name: ${name}, Age: ${age ?? 'no age'}`);
}printInfo("张三");      // "Name: 张三, Age: no age"
printInfo("李四", 25);  // "Name: 李四, Age: 25" 
printInfo("王二", 0);   // "Name: 王二, Age: 0" 

可选参数必须跟在必须参数后面。
这是为了确保在调用函数时,必需的参数能够按照正确的顺序被传递,而不会因为可选参数的存在导致参数传递的混乱。

默认参数

可以为参数指定一个默认值,如果调用函数时没有传递该参数或传递的值是undefined时,就会使用默认值。

function printInfo(name: string, age: number = 18) {console.log(`Name: ${name}, Age: ${age}`);
}
printInfo("张三");      // "Name: 张三, Age: 18" 
printInfo("李四", 25);  // "Name: 李四, Age: 25" 
printInfo("王二", undefined);   // "Name: 王二, Age: 18" 

当一个参数在所有必需参数之后并且有默认初始化值时,它就具有了可选的性质。
printInfo 函数中,age 参数具有默认值 18 ,所以在调用函数时可以省略它,就像可选参数一样。

与普通可选参数不同的是,带默认值的参数不需要放在必须参数的后面。 如果带默认值的参数出现在必须参数前面,用户必须明确的传入 undefined值来获得默认值。
示例:

function printInfo(name: string = "张三", age: number) {console.log(`Name: ${name}, Age: ${age}`);
}
printInfo(undefined, 18);   // "Name: 张三, Age: 18" 
printInfo("李四", 25);      // "Name: 李四, Age: 25" // 假如只传入 age 
printInfo(25); // Error: Expected 2 arguments, but got 1.

剩余参数

必要参数、默认参数、可选参数有个共同点:它们表示某一个参数。
有时,想同时操作多个参数,或者并不知道会有多少参数传递进来。 在JavaScript里,你可以使用 arguments来访问所有传入的参数。

在 TypeScript 中,剩余参数用于表示不确定数量的参数。它使用 ... 语法来定义。
剩余参数会被当做个数不限的可选参数。 可以一个都没有,同样也可以有任意个。

function sumAll(numbers: number[], ...restNum: number[]) {let total = 0;for (const num of numbers) {total += num;}for (const num of restNum) {total += num;}return total;
}// 没有剩余参数
console.log(sumAll([1, 2, 3])); // 6// 有 3 个剩余参数
console.log(sumAll([1, 2, 3], 4, 5, 6));  // 21

在为带有剩余参数的函数定义类型时,也需要正确地表示剩余参数的部分。
实现 sumAll 函数的类型定义:

let myFunction: (numbers: number[], ...restNum: number[]) => number = sumAll;// 参数名字可以不一样,但是参数的类型必须一样
let myFunc: (nums: number[], ...rest: number[]) => number = sumAll;

this和箭头函数

在普通函数中,this 的值取决于函数的调用方式。如果是作为对象的方法被调用,this 指向该对象;如果是独立调用,非严格模式下,this 通常指向全局对象(在浏览器环境中是 window,在 Node.js 环境中是 global)。严格模式下, thisundefined

非严格模式下:

// 作为对象的方法被调用
let obj = {method: function() {console.log(this);  // 这里的 this 指向 obj 对象}
};
obj.method();// 独立调用
function standalone() {console.log(this);  // 在浏览器中,这里的 this 指向 window 对象
}
standalone();

严格模式下:

// 作为对象的方法被调用
let strictObj = {strictMethod: function() {"use strict";console.log(this);  // 这里的 this 指向 strictObj 对象}
};
strictObj.strictMethod();// 独立调用
function strictStandalone() {"use strict";console.log(this);  // 这里的 this 是 undefined
}
strictStandalone();

可以在浏览器中执行代码来验证结果。

箭头函数中的 this 继承自其定义时所在的上下文,不会因为调用方式的不同而改变。

let obj = {method: () => {// "use strict";console.log(this); // 在浏览器中,这里的 this 指向 window 对象}
};
obj.method();

这段代码中,无论是严格模式还是非严格模式,this 都指向 window 对象。
箭头函数 method 是在对象 obj 中定义的,由于是箭头函数,this 并不指向 obj ,而是继承了外部(即全局)的 this 值。在浏览器环境中,全局的 this 就是 window 对象。

使 this 指向obj

let obj = {width: 10,height: 10,method() {return () => {return console.log(this)}}
};
obj.method()();// 把obj.method()赋值给method变量
let method = obj.method();
method()

在这里插入图片描述
由上图运行结果可知,箭头函数里的 this 指向obj。此时,this 的 类型 是 any

this 参数

在 TypeScript 中,this 可以被显式地作为参数添加到函数的参数列表中,用于更明确地控制和处理函数内部的 this 指向。

提供一个显式的 this 参数, 让this 的类型不是any

interface OBJ {width: number;height: number;method(this: OBJ): () => number;
}let obj: OBJ = {width: 10,height: 10,method(this: OBJ) {return () => {return this.width + this.height}}
};
console.log(obj.method()()); // 20let method = obj.method(); 
console.log(method); // 20

这段代码中,thisOBJ 类型的。不论如何调用method()this始终指向OBJ

this参数在回调函数里

当把一个函数作为回调传递给库函数,并且在回调函数中使用了 this 时,确实经常会遇到 this 指向错误或为 undefined 的问题。
这是因为函数的调用方式会影响 this 的指向。如果回调函数被库函数以普通函数的方式调用,而不是作为对象的方法调用,那么 this 就不会指向预期的对象,通常会是 undefined
例如,假设有一个库函数 doAsyncOperation ,它接受一个回调函数:

function doAsyncOperation(callback: () => void) {// 模拟异步操作完成后调用回调setTimeout(callback, 1000);
}

然后有一个类 MyClass ,其中有一个方法想要在回调中使用 this

class MyClass {data: string = "Some data";performOperation() {doAsyncOperation(this.someCallback);}someCallback() {console.log(this.data);  // undefined}
}
let myC = new MyClass();
myC.performOperation();

执行myC.performOperation()语句, doAsyncOperation 内部以普通函数的方式调用 callback ,当 doAsyncOperation 调用回调函数时,this 不是指向 MyClass 的实例,而是 undefined ,导致无法访问 data 属性。回调函数的输出结果为undefined

因为在 setTimeout 内部,如果传递的回调函数是一个普通函数,那么 this 的指向取决于运行环境和调用方式。

在非严格模式下,如果是在浏览器环境中,this 通常指向 window 对象;在 Node.js 环境中,this 通常指向 global 对象。
在严格模式下,this 的值会是 undefined

someCallback 改为箭头函数:

class MyClass {data: string = "Some data";performOperation() {doAsyncOperation(this.someCallback);}someCallback = () => {console.log(this.data);  // "Some data"}
}
let myC = new MyClass();
myC.performOperation();

在上述代码中,someCallback 被定义为箭头函数。
箭头函数不会创建自己的 this 上下文,而是继承外层(即定义它的 MyClass 实例)的 this 上下文。
doAsyncOperation 函数中的异步操作完成并调用 callback (即 this.someCallback )时,由于 someCallback 是箭头函数,它所使用的 this 仍然是其定义时所在的 MyClass 实例的 this
所以,在 someCallback 函数内部,能够正确访问到 MyClass 实例的属性 data ,并将其打印出来,即输出结果为 “Some data” 。

或者:

class MyClass {data: string = "Some data";performOperation() {doAsyncOperation(() => this.someCallback());}someCallback() {console.log(this.data);  // "Some data"}
}
let myC = new MyClass();
myC.performOperation();

doAsyncOperation(() => this.someCallback()); 中,使用了一个立即执行的箭头函数。
箭头函数不会创建自己的 this 上下文,而是继承外层(即定义它的 MyClass 实例)的 this 上下文。
在这个箭头函数内部,this 正确地指向了 MyClass 的实例。

上面这个例子比较简单,再举一个复杂一点的例子。
例如,假设有一个库函数 UIElement ,库函数的作者要指定 this的类型:

interface UIElement {addClickListener(onclick: (this: void, e: CustomEvent,  params?: {[propName: string]: any}) => void): void;
}

有一个Handler类,处理自定义事件以及在不同类型的回调函数中处理数据和 this 的指向。

class Handler {info: string = "";onClickGood(this: void, e: CustomEvent) {// 通过指定 this: void ,表明该回调函数在被调用时不期望或不依赖于特定的 this 上下文。console.log(this); // undefinedconsole.log("clicked!");}onClickGood2 = (e: CustomEvent) => {// 箭头函数,this 指向 Handlerthis.info = e.detail.message;};doOther (this: void, e: CustomEvent, params?: {[propName: string]: any}) {// 在这里根据传入的 params 进行相应的处理// 如果要操作this,就使用箭头函数。console.log(e.detail.message);console.log(params);};
}let h = new Handler();
let uiElement: UIElement = {addClickListener(onclick) {const event = new CustomEvent("click", { detail: { message: "Hello" } });onclick(event);}
};uiElement.addClickListener(h.onClickGood);
uiElement.addClickListener(h.onClickGood2);let uiElementDo: UIElement = {addClickListener(onclick) {const event = new CustomEvent("click", { detail: { message: "输出用户的输入" } });let word = prompt("输入你想说的话", "");let params = {word: word}onclick(event, params);}
};uiElementDo.addClickListener(h.doOther)

函数重载

在 TypeScript 中,函数重载是指可以为同一个函数定义多个不同的签名(参数类型和返回类型的组合)。
示例:

function add(a: number, b: number): number;
function add(a: string, b: string): string;function add(a: any, b: any): any {if (typeof a === 'number' && typeof b === 'number') {return a + b;}if (typeof a ==='string' && typeof b ==='string') {return `${a} ${b}`;}throw new Error('Invalid parameters');
}console.log(add(1, 2));  // 3
console.log(add('hello', 'world')); // "hello world" 

在上述示例中,add 函数有两个不同的函数签名:一个接受两个数字参数并返回一个数字,另一个接受两个字符串参数并返回一个字符串。

函数的实现部分根据传入参数的类型来决定执行不同的逻辑。

相关文章:

TypeScript 函数

函数是JavaScript应用程序的基础。 它帮助你实现抽象层,模拟类,信息隐藏和模块。 在TypeScript里,虽然已经支持类,命名空间和模块,但函数仍然是主要的定义 行为 的地方。 TypeScript为JavaScript函数添加了额外的功能&…...

C++ : namespace,输入与输出,函数重载,缺省参数

一,命名空间(namespace) 1.1命名空间的作用与定义 我们在学习c的过程中,经常会碰到命名冲突的情况。就拿我们在c语言中的一个string函数来说吧: int strncat 0; int main() {printf("%d", strncat);return 0; } 当我们运行之后&…...

目标检测 | yolov1 原理和介绍

1. 简介 论文链接:https://arxiv.org/abs/1506.02640 时间:2015年 作者:Joseph Redmon 代码参考:https://github.com/abeardear/pytorch-YOLO-v1 yolo属于one-stage算法,仅仅使用一个CNN网络直接预测不同目标的类别与…...

excel中有些以文本格式存储的数值如何批量转换为数字

一、背景 1.1 文本格式存储的数值特点 在平时工作中有时候会从别地方导出来表格,表格中有些数值是以文本格式存储的(特点:单元格的左上角有个绿色的小标)。 1.2 文本格式存储的数值在排序时不符合预期 当我们需要进行排序的时候…...

原神升级计划数据表:4个倒计时可以修改提示信息和时间,可以点击等级、命座、天赋、备注进行修改。

<!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><title>原神倒计时</title><style>* {margin: 0;padding: 0;box-sizing: border-box;body {background: #0b1b2c;}}header {width: 100vw;heigh…...

YoloV10 论文翻译(Real-Time End-to-End Object Detection)

​摘要 近年来&#xff0c;YOLO因其在计算成本与检测性能之间实现了有效平衡&#xff0c;已成为实时目标检测领域的主流范式。研究人员对YOLO的架构设计、优化目标、数据增强策略等方面进行了探索&#xff0c;并取得了显著进展。然而&#xff0c;YOLO对非极大值抑制&#xff0…...

第R1周:RNN-心脏病预测

本文为&#x1f517;365天深度学习训练营 中的学习记录博客 原作者&#xff1a;K同学啊 要求&#xff1a; 1.本地读取并加载数据。 2.了解循环神经网络&#xff08;RNN&#xff09;的构建过程 3.测试集accuracy到达87% 拔高&#xff1a; 1.测试集accuracy到达89% 我的环境&a…...

Golang | Leetcode Golang题解之第321题拼接最大数

题目&#xff1a; 题解&#xff1a; func maxSubsequence(a []int, k int) (s []int) {for i, v : range a {for len(s) > 0 && len(s)len(a)-1-i > k && v > s[len(s)-1] {s s[:len(s)-1]}if len(s) < k {s append(s, v)}}return }func lexico…...

远程连接本地虚拟机失败问题汇总

前言 因为我的 Ubuntu 虚拟机是新装的&#xff0c;并且应该装的是比较纯净的版本&#xff08;纯净是指很多工具都尚未安装&#xff09;&#xff0c;然后在使用远程连接工具 XShell 连接时出现了很多问题&#xff0c;这些都是我之前没遇到过的&#xff08;因为之前主要使用云服…...

WebRTC 初探

前言 项目中有局域网投屏与文件传输的需求&#xff0c;所以研究了一下 webRTC&#xff0c;这里记录一下学习过程。 WebRTC 基本流程以及概念 下面以 1 对 1 音视频实时通话案例介绍 WebRTC 的基本流程以及概念 WebRTC 中的角色 WebRTC 终端,负责音视频采集、编解码、NAT 穿…...

Python:read,readline和readlines的区别

在Python中&#xff0c;read(), readline(), 和 readlines() 是文件操作中常用的三个方法&#xff0c;它们都用于从文件中读取数据&#xff0c;但各自的使用方式和适用场景有所不同。 read() 方法&#xff1a; read(size-1) 方法用于从文件中读取指定数量的字符。如果指定了si…...

重生之我学编程

编程小白如何成为大神&#xff1f;大学新生的最佳入门攻略 编程已成为当代大学生的必备技能&#xff0c;但面对众多编程语言和学习资源&#xff0c;新生们常常感到迷茫。如何选择适合自己的编程语言&#xff1f;如何制定有效的学习计划&#xff1f;如何避免常见的学习陷阱&…...

如何将PostgreSQL的数据实时迁移到SelectDB?

PostgreSQL 作为一个开源且功能强大的关系型数据库管理系统&#xff0c;在 OLTP 系统中得到了广泛应用。很多企业利用其卓越的性能和灵活的架构&#xff0c;应对高并发事务、快速响应等需求。 然而对于 OLAP 场景&#xff0c;PostgreSQL 可能并不是最佳选择。 为了实现庞大规…...

关于c语言的const 指针

const * type A 指向的数据是常量 如上所示&#xff0c;运行结果如下&#xff0c;通过解引用的方式&#xff0c;改变了data的值 const type * A 位置是常量&#xff0c;不能修改 运行结果如下 type const * A 指针是个常量&#xff0c;指向的值可以改变 如上所示&#xff0c…...

万能门店小程序开发平台功能源码系统 带完整的安装代码包以及安装搭建教程

互联网技术的迅猛发展和用户对于便捷性需求的不断提高&#xff0c;小程序以其轻量、快捷、无需安装的特点&#xff0c;成为了众多商家和开发者关注的焦点。为满足广大商家对于门店线上化、智能化管理的需求&#xff0c;小编给大家分享一款“万能门店小程序开发平台功能源码系统…...

C#初级——字典Dictionary

字典 字典是C#中的一种集合&#xff0c;它存储键值对&#xff0c;并且每个键与一个值相关联。 创建字典 Dictionary<键的类型, 值的类型> 字典名字 new Dictionary<键的类型, 值的类型>(); Dictionary<int, string> dicStudent new Dictionary<int, str…...

git版本控制的底层实现

目录 前言 核心概念串讲 底层存储形式探测 本地仓库的详细解析 提交与分支的深入解析 几个问题的深入探讨 前言 Git的重要性 Git是一个开源的版本控制工具&#xff0c;广泛用于编程开发领域。它极大地提高了研发团队的开发协作效率。对于开发者来说&#xff0c;Git是一个…...

深入解析数据处理的技术与实践

欢迎来到我的博客,很高兴能够在这里和您见面!欢迎订阅相关专栏: 工💗重💗hao💗:野老杂谈 ⭐️ 全网最全IT互联网公司面试宝典:收集整理全网各大IT互联网公司技术、项目、HR面试真题. ⭐️ AIGC时代的创新与未来:详细讲解AIGC的概念、核心技术、应用领域等内容。 ⭐…...

python-调用c#代码

环境&#xff1a; win10&#xff0c;net framework 4&#xff0c;python3.9 镜像&#xff1a; C#-使用IronPython调用python代码_ironpython wpf-CSDN博客 https://blog.csdn.net/pxy7896/article/details/119929434 目录 hello word不接收参数接收参数 其他例子 hello word 不…...

构建铁路安全防线:EasyCVR视频+AI智能分析赋能铁路上道作业高效监管

一、方案背景 随着我国铁路特别是高速铁路的快速发展&#xff0c;铁路运营里程不断增加&#xff0c;铁路沿线的安全环境对保障铁路运输的安全畅通及人民群众的生命财产安全具有至关重要的作用。铁路沿线安全环境复杂多变&#xff0c;涉及多种风险因素&#xff0c;如人员入侵、…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

CSS设置元素的宽度根据其内容自动调整

width: fit-content 是 CSS 中的一个属性值&#xff0c;用于设置元素的宽度根据其内容自动调整&#xff0c;确保宽度刚好容纳内容而不会超出。 效果对比 默认情况&#xff08;width: auto&#xff09;&#xff1a; 块级元素&#xff08;如 <div>&#xff09;会占满父容器…...

纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join

纯 Java 项目&#xff08;非 SpringBoot&#xff09;集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量&#xff1a;setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...