TypeScript 学习笔记(三):函数

一、函数定义

函数是由一连串的子程序(语句的集合)所组成的,可以被外部程序调用,向函数传递参数之后,函数可以返回一定的值。

通常情况下,TypeScript 代码是自上而下执行的,不过函数体内部的代码则不是这样。如果只是对函数进行了声明,其中的代码并不会执行,只有在调用函数时才会执行函数体内部的代码。

二、函数格式类型

1. 函数定义类型:

function add(arg1: number, arg2: number): number {
  return x + y;
}
// 或者
const add = (arg1: number, arg2: number): number => {
  return x + y;
};

上面例子中参数 arg1 和 arg2 都是数值类型,最后通过相加得到的结果也是数值类型。

如果在这里省略参数的类型,TypeScript 会默认这个参数是 any 类型;如果省略返回值的类型,如果函数无返回值,那么 TypeScript 会默认函数返回值是 void 类型;如果函数有返回值,那么 TypeScript 会根据我们定义的逻辑推断出返回类型。

2. 完整的函数类型

一个函数的定义包括函数名、参数、逻辑和返回值。我们为一个函数定义类型时,完整的定义应该包括参数类型和返回值类型。上面的例子中,我们都是在定义函数的指定参数类型和返回值类型。接下来我们看下,如何定义一个完整的函数类型,以及用这个函数类型来规定一个函数定义时参数和返回值需要符合的类型。先来看例子然后再进行解释:

let add: (x: number, y: number) => number;
add = (arg1: number, arg2: number): number => arg1 + arg2;
add = (arg1: string, arg2: string): string => arg1 + arg2; // error
 

上面这个例子中,我们首先定义了一个变量 add,给它指定了函数类型,也就是(x: number, y: number) => number,这个函数类型包含参数和返回值的类型。然后我们给 add 赋了一个实际的函数,这个函数参数类型和返回类型都和函数类型中定义的一致,所以可以赋值。后面我们又给它赋了一个新函数,而这个函数的参数类型和返回值类型都是 string 类型,这时就会报如下错误:
在这里插入图片描述
函数中如果使用了函数体之外定义的变量,这个变量的类型是不体现在函数类型定义的。

3. 使用接口定义函数类型

interface Add {
  (x: number, y: number): number;
}
let add: Add = (arg1: string, arg2: string): string => arg1 + arg2; // error 不能将类型“(arg1: string, arg2: string) => string”分配给类型“Add”
 

在这里插入图片描述

4. 使用类型别名

type Add = (x: number, y: number) => number;
let add: Add = (arg1: string, arg2: string): string => arg1 + arg2; // error 不能将类型“(arg1: string, arg2: string) => string”分配给类型“Add”
 

使用type关键字可以为原始值、联合类型、元组以及任何我们定义的类型起一个别名。上面定义了 Add 这个别名后,Add就成为了一个和(x: number, y: number) => number一致的类型定义。例子中定义了Add类型,指定add类型为Add,但是给add赋的值并不满足Add类型要求,所以报错。

三、参数

1. 必选参数

必选参数:在调用函数的时候,必须要传入的参数,参数列表里边的参数默认就是必选参数,只要在声明的时候写了参数,在传递的时候,就必须传入参数,而且,实参与形参的数量与类型要一致。

type Add = (x: number, y: number) => number;
let add: Add = (arg1: string, arg2: string): string => arg1 + arg2;
 
add(1, 2); // right
add(1, 2, 3); // error 应有 2 个参数,但获得 3 个
add(1); // error 应有 2 个参数,但获得 1 个
 

2. 可选参数

可选参数:为了解决在函数传参的时候,某些参数可以不用传递,我们就需要可选参数了

function getInfo(name: string, age?: number): string {
    return `${name} --- ${age}`;
}

console.log(getInfo("张三", 28)); // 正确
console.log(getInfo("张三")); // 正确
console.log(getInfo(28)); // 错误

type Add = (x?: number, y: number) => number; // error 必选参数不能位于可选参数后。
 

注意:可选参数必须配置到参数的最后面。

3. 默认参数

默认参数:为了解决在函数传参的时候,某些参数可以不用传递,但是我们又需要该参数的值,这时候我们就需要给这个参数设定一个默认值也叫初始化值,就得用到默认参数了。

function getInfo(name: string, age: number = 20): string {
    return `${name} --- ${age}`;
}

console.log(getInfo("张三", 28)); // 正确
console.log(getInfo("张三")); // 正确
console.log(getInfo(28)); // 错误

注意:可选参数不能够进行初始化值的设定。

4. 剩余参数

剩余参数:在参数的类型确定而参数个数不确定的情况时,我们需要用到剩余参数,它使用 … 将接收到的参数传到一个指定类型的数组中。

function sum(...result: number[]): number {
    let sum = 0;
    for (let i = 0; i < result.length; i++) {
        sum += result[i];
    }
    return sum;
}

console.log(sum(1, 2, 3, 4, 5, 6));

function sum(init: number, ...result: number[]): number {
    let sum = init;
    for (let i = 0; i < result.length; i++) {
        sum += result[i];
    }
    return sum;
}

console.log(sum(100, 1, 2, 3, 4, 5, 6));

注意:剩余参数必须配置到参数的最后面。

四、函数重载

1. 函数签名

函数签名主要定义了参数及参数类型,返回值及返回值类型。函数签名不同,函数会做出不同的处理。

2. 构造器重载

举个例子,声明一个类Course,里面写一个begin的方法,我们调用 begin时传入不同参数类型已经参数个数,begin方法会做出不同处理,那么怎么实现呢?4个重载签名和1个实现签名具体如下:

type Combinable = number | string;
class Course {
   //定义重载签名
   begin(name: number, score: number): string;
   begin(name: string, score: string): string;
   begin(name: string, score: number): string;
   begin(name: number, score: string): string;
   //定义实现签名
   begin(name: Combinable, score: Combinable) {
       if (typeof name === 'string' || typeof score === 'string') {
           return 'student:' + name + ':' + score; 
       }
   }
}

const course = new Course();
console.log(course.begin(111, 5)); //没有输出
console.log(course.begin('zhangsan', 5)); //student:zhangsan:5
console.log(course.begin(5, 'zhangsan')); //student:5:zhangsan

3. 联合类型函数重载

声明一个函数uniteFunctionOverloading,参数类型为联合类型,返回值也是联合类型,但是如下代码却报错了。

function uniteFunctionOverloading(x: number | string): number | string {
    if (typeof x === 'number') {
        return x;
    } else {
        return x+'是字符串';
    }
}
uniteFunctionOverloading(1).toFixed(1); // 报错 类型“string | number”上不存在属性“toFixed”。类型“string”上不存在属性“toFixed”

我们可以可以根据传参的类型和函数返回值声明多个同名的函数,只是类型和返回值不同而已。

function uniteFunctionOverloading(x: number): number;
function uniteFunctionOverloading(x: string): string; 
function uniteFunctionOverloading(x: number | string): number | string {
    if (typeof x === 'number') {
        return x;
    } else {
        return x+'是字符串';
    }
}
uniteFunctionOverloading(1).toFixed(1);

这样就不会报错了,可以利用重载将多种情况声明这样就可推导类型更细致,因为已经识别到uniteFunctionOverloading(1)的返回值是number类型。

五、拓展JS中函数重载

1. 利用arguments参数

var arr = [1,2,3,4,5];
//注意:这里不能写成箭头函数,否则this指向的是window对象
Array.prototype.search = function() {
   var len = arguments.length;
   switch(len){
   case 0:
	 return this;
   case 1:
	 return `${arguments[0]}`;
   case 2:
	 return `${arguments[0]},${arguments[1]}`;
  }
}
console.log(arr.search()) //[1,2,3,4,5]
console.log(arr.search(1)) //1
console.log(arr.search(1,2)) //1,2

2. 利用闭包和arguments

 function addMethod (obj, name, fn) {
        var old = obj[name];
        obj[name] = function () {
            if (fn.length === arguments.length) {
                return fn.apply(this, arguments)
            } else if (typeof old === 'function') {
                return old.apply(this, arguments)
            }
        }
    }

    var person = {name: 'zhangsan'}
    addMethod(person, 'getName', function () {
        console.log(this.name + '---->' + 'getName1')
    })
    addMethod(person, 'getName', function (str) {
        console.log(this.name + '---->' + str)
    })
    addMethod(person, 'getName', function (a, b) {
        console.log(this.name + '---->' + (a + b))
    })
    person.getName()  
    person.getName('zhangsan')
    person.getName(10, 20)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SELECT * 会导致查询效率低的原因

SELECT * 会导致查询效率低的原因 前言一、适合SELECT * 的使用场景二、SELECT * 会导致查询效率低的原因2.1、数据库引擎的查询流程2.2、SELECT * 的实际执行过程2.3、使用 SELECT * 查询语句带来的不良影响 三、优化查询效率的方法四、总结 前言 因为 SELECT * 查询语句会查…

Spring整合Elasticsearch

启动Elasticsearch的集群,如果不会搭建集群可以看我以前的文章 进入到head的扩展应用,连接后面的健康值为green就表示集群没问题 Spring Data Elasticsearch 特征: Spring配置支持使用基于Java的 Configuration 类或ES客户端实例的XML命名空间。 Elasticsearc…

谈一谈LLM在推荐域的一些理解

作者&#xff1a;陈祖龙(葬青) 一、前言 最近大模型真的很火&#xff0c;从个人到公司&#xff0c;各行各业都在学习大模型、总结大模型和尝试应用大模型。大模型其实不是一个新的产物&#xff0c;已经在NLP发展了很多年。ChatGPT的诞生&#xff0c;经验的效果震惊了所有人&…

Java设计模式之结构型-外观模式(UML类图+案例分析)

目录 一、基础概念 二、UML类图 三、角色设计 四、案例分析 五、总结 一、基础概念 外观模式&#xff0c;为子系统中的一组接口提供一个一致的界面&#xff0c;此模式定义了一个高层接口&#xff0c;这个接口使得这一子系统更加容易使用。 二、UML类图 三、角色设计 角…

初识Spring - 什么是IoC容器?

目录 一、Spring是什么&#xff1f; Spring就是包含了很多工具方法的 IoC 容器。 1. 什么是IoC&#xff0c;什么是容器 2. IoC的优点 (解决耦合问题) 二、什么是Spring IoC 1. Spring IoC详解 &#xff08;1&#xff09;也就是学习 Spring 最核心的功能&#xff1a; &…

Redis主从哨兵模式

IP 服务 用途 10.0.10.45 redis sentinel zookeeper uniquecode 主redis 10.0.10.43 redis sentinel zookeeper uniquecode 从reids-1 10.0.10.44 redis sentinel zookeeper uniquecode 从redis-2 redis主从哨兵分为两部分&#xff0c;redis主从和redis哨兵 redi…

【分布式】 ELK 企业级日志分析系统 二

目录 一、FilebeatELK 部署1.1 环境部署 二、grok 正则捕获插件mutate 数据修改插件multiline 多行合并插件date 时间处理插件 一、FilebeatELK 部署 1.1 环境部署 Node1节点&#xff08;2C/4G&#xff09;&#xff1a;node1/192.168.137.101 Elasticsearch Node2节点&…

反常积分定义

目录 反常积分的定义 判断敛散性的方法 方法2&#xff1a; 例题 无界函数的反常积分 判断敛散性的方法 例题 反常积分的定义 该极限存在就表示该反常积分收敛 对于定义3&#xff0c;只有两个都收敛的情况下&#xff0c;原反常积分才收敛。 判断敛散性的方法 始终大的函数形成…

ACWing算法基础课

y总说 java不能用Scanner读入,要用Buffer.read();快十倍二十倍; y总19年5月的视频,牛13! 第一讲 基础算法 包括排序、二分、高精度、前缀和与差分、双指针算法、位运算、离散化、区间合并等内容。 快速排序 一定要先移动end(就是把大数移到右边),后移动start; 否则 先找…

【云原生|Docker系列第2篇】Docker的安装和配置

欢迎来到Docker入门系列的第二篇博客&#xff01;在上一篇博客中&#xff0c;我们已经介绍了Docker的基本概念和作用&#xff0c;以及为什么它成为现代应用开发和部署的关键技术。本篇博客将着重讨论Docker的安装和配置&#xff0c;帮助您开始使用Docker并为您的应用程序提供一…

第十章——对象和类

面向对象编程&#xff08;OOP&#xff09;是一种特殊的、设计程序的概念性方法&#xff0c;下面是最重要的OOP特性&#xff1a; 抽象封装和数据隐藏多态继承代码的可重用性 为了实现这些特性并将它们组合在一起&#xff0c;C所做的最重要的是提供了类 采用过程性编程首先考虑…

OpenCV 入门教程:像素访问和修改

OpenCV 入门教程&#xff1a;像素访问和修改 导语一、像素访问1.1 获取图像的大小1.2 访问图像的像素值1.3 修改图像的像素值 二、示例应用2.1 图像反转2.2 阈值化操作 三、总结 导语 在图像处理和计算机视觉领域&#xff0c;像素级操作是非常重要和常见的任务之一。通过像素访…

Oracle的CentOS安装

1.CentOS环境 阿里云轻量型服务器 2核-4g内存-80G系统盘 2.Oracle下载 Oracle下载 Oracle 数据库免费 CPU 限制 Oracle 数据库免费版自动将自身限制为两个内核进行处理。例如&#xff0c;在具有 2 个双核 CPU&#xff08;四个核&#xff09;的计算机上&#xff0c;如果大量…

mac批量在文件名前面加相同文字?

mac批量在文件名前面加相同文字&#xff1f;你平时在使用电脑进行工作或者学习的时候&#xff0c;是不是需要做一些关于文件整理和保存的操作呢&#xff0c;并且还需要对一大堆的文件进行重名呢&#xff1f;相信很大多数小伙伴都要面对这些&#xff0c;经常需要将大量文件的名称…

SpringBoot学习——追根溯源servlet是啥,tomcat是啥,maven是啥 springBoot项目初步,maven构建,打包 测试

目录 引出追根溯源&#xff0c;过渡衔接servlet是啥&#xff1f;tomcat是啥&#xff1f; 前后端开发的模式1.开发模式&#xff1a;JavaWeb&#xff1a;MVC模型2.Web&#xff1a;Vue&#xff0c;MVVC模型3.后端相关3.1 同步与异步3.2 Controller层3.3 Service层&#xff1a;要加…

阐述kubernetes部署:基础设施安装

基础设施部署 持久卷的建立 请参考&#xff1a;《持久卷的建立》 elasticsearch部署 一、设置远程扩展字典 不使用自定义字典请忽略此步骤 首先更改ES中IK插件的配置&#xff1a; vi/opt/kubernetes/es/IKAnalyzer.cfg.xml 按您的实际设置的秘钥配置secret_value&#xff1a; …

华为配置LLDP基本功能

华为配置LLDP基本功能 1.什么是lldp协议 定义 LLDP(Link Layer Discovery Protocol)是IEEE 802.1ab中定义的链路层发现协议。LLDP是一种标准的二层发现方式,可以将本端设备的管理地址、设备标识、接口标识等信息组织起来,并发布给自己的邻居设备,邻居设备收到这些信息后将…

git提交只单个或者某几个文件的指令

git status --查看目前本地和远程仓库的差异&#xff1b; git add --提交某的文件&#xff0c;多次执行可以提交多个文件 文件名称替换 git stash -u -k --其他文件保留到本地暂存区&#xff0c;不进行提交 git commit -m ---针对本次修改添加注释并提交到远程仓库 gi…

在安卓手机搭建kali环境,手机变成便携式渗透神器

简介 kali是著名的黑客专用系统&#xff0c;一般都是直接装在物理机或者虚拟机上&#xff0c;我们可以尝试把kali安装在手机上&#xff0c;把手机打造成一个便携式渗透神器。 我们需要下载以下3款软件&#xff1a; (1).Termux(终端模拟器) (2).AnLinux(里边有各种安装liunx…

从零实现深度学习框架——带Attentiond的Seq2seq机器翻译

引言 本着“凡我不能创造的,我就不能理解”的思想,本系列文章会基于纯Python以及NumPy从零创建自己的深度学习框架,该框架类似PyTorch能实现自动求导。 要深入理解深度学习,从零开始创建的经验非常重要,从自己可以理解的角度出发,尽量不使用外部完备的框架前提下,实现我…
最新文章