TypeScript中的函数和类你了解吗

目录
  • 函数
    • 作为参数
    • 定义函数
    • 函数参数的类型
    • 可选类型
    • 参数默认值
    • 剩余参数
    • this的默认推导
    • 函数重载
    • 初始化
    • 继承
    • 多态
    • 成员修饰符
  • 总结

函数

以下声明了一个函数类型,通过type来定义类型别名,void 表示没有返回值

type fnType = () => void;

作为参数

函数可以作为参数,传递到另一个函数中

type fnType = () => void;
function foo(fn: fnType) {
  fn();
}
function bar() {
  console.log("bar");
}
foo(bar);      // bar

与js代码不同的点在于传入的参数需要定义类型注解

定义函数

定义函数的时候,需要给入参指定类型注解,返回值如果可以自行推导出来,也可以不写,如 add 和 minus 函数,但是作为参数时,是必须要写的,如 calc 函数中的入参 fn

function add(num1: number, num2: number): number {
  return num1 + num2;
}
function minus(num1: number, num2: number): number {
  return num1 - num2;
}
function calc(
  num1: number,
  num2: number,
  fn: (num1: number, num2: number) => void
) {
  console.log(fn(num1, num2));
}
calc(30, 20, add);      // 50
calc(30, 20, minus);      // 10

函数参数的类型

ts中函数会规定参数的类型和个数,当个数不确定时,可以使用可选类型、剩余参数、默认值

可选类型

可选类型相当于该定义的类型和undefined的联合类型,所以参数有三种选择、传入该类型、不传或者undefined

function foo(x: number, y?: number) {
  console.log(x, y);
}
foo(1, 2);      // 1 2
foo(3);      // 3 undefined
foo(4, undefined);      // 4 undefined

参数默认值

参数设置了默认值就使之称为了可选类型,不过有默认值的参数最好放在必传参数后面

function baz(x: number = 20, y: number) {
  console.log(x, y);
}
baz(10, 20);      // 10 20
baz(undefined, 20);      // 20 20

剩余参数

剩余参数要放在必传参数之后

function sum(num: number, ...args: number[]) {
  console.log(num, args);
}
sum(10);      // 10 []
sum(10, 20);      // 10 [20]
sum(10, 20, 30);      // 10 [20, 30]

this的默认推导

在对象的方法中定义的this,ts是可以自动推导的,但是独立函数中的this,是推导不出来的。

必须要在独立函数中定义this的类型

type ThisType = { name: string };
const eating = function (this: ThisType) {
  console.log(this.name + " eating~");
};
const person = {
  name: "kiki",
  eating,
};
person.eating()

函数重载

函数重载指的是函数名相同,参数个数或者类型不同,所定义的多个处理方法。

比如需要对字符串拼接或者数字求和操作,虽然我们知道 + 号可以用在字符串和数字上,但是在类型检测严格的ts代码中,这样写编译是不通过的,需要使用【类型缩小】,缩小类型的判断,再进行处理。

通过联合类型,参数组合的可能性越多,需要越多的if语句来进行判断,并且函数的返回值类型也是未知的,在这种情况下可以使用【函数重载】

在ts中,定义函数名和参数类型的重载函数,再通过实现函数来定义具体实现。 会根据数据类型在重载函数中调用,再执行实现函数的代码。

function add(x: number, y: number): number;
function add(x: string, y: string): string;
function add(x: any, y: any) {
  return x + y;
}
console.log(add(1, 2));
console.log(add("a", "b"));

如果传递的参数与重载函数中定义参数不同,是无法通过编译的。

初始化

类中定义的变量需要初始化,可以在定义类的时候就赋值或者通过constructor来操作

class Person {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}
const person = new Person("alice", 20);

继承

ts和js中一致,都是通过 extends 实现继承,使用父级参数和方法时使用 super 关键字。

class Person {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}
class Student extends Person {
  sno: number;
  constructor(name: string, age: number, sno: number) {
    super(name, age);
    this.sno = sno;
  }
}
const student = new Student("alice", 20, 1);

多态

使用多态可以写出更加具备通用性的代码,如果想要实现多态首先得有继承,并且父类引用指向子类对象。

class Animal {
  action() {
    console.log("animal action");
  }
}
class Dog extends Animal {
  action() {
    console.log("dog running");
  }
}
class Fish extends Animal {
  action() {
    console.log("fish swimming");
  }
}
function doAction(animals: Animal[]) {
  animals.forEach((animal) => {
    animal.action();
  });
}
doAction([new Dog()]);
doAction([new Dog(), new Fish()]);
doAction([new Dog(), new Fish(), new Animal()]);

这里相当于 const animal1: Animal = new Dog() ,看起来是 Animal 对象,其实是 Dog 对象,这里的父类引用指向的是子类对象,所以最后执行的是 Dog 对象的方法

成员修饰符

成员修饰符有以下三种

  • public 表示共有的,任何地方都可见,当没有定义成员修饰符时,默认为public
  • private 私有的,只有类中能够访问到
  • protected 被保护的,表示类自身和子类可以访问到

public

class Person {
  public username: string = "alice";
  getName() {
    return this.username;
  }
}
const person = new Person();
console.log(person.username);

private

通过private修饰的变量,在实例对象上也是不可访问的。

protected

通过protected修饰的变量,在实例对象上也是不可访问的。

readonly

readonly表示该属性只读,初始化了之后就不能以任何方式修改,无论是在类内部,还是修改实例对象,但当它是一个对象时,只要不改变它的内存地址,修改对象的属性是可以的。

访问器

访问器给私有属性提供get/set方法,让我们在类外部获取/修改私有属性

class Person {
  private _name: string;
  constructor(newName: string) {
    this._name = newName;
  }
  get name() {
    return this._name;
  }
  set name(newName) {
    if (newName) this._name = newName;
  }
}
const person = new Person("alice");
console.log(person.name);
person.name = "kiki";
console.log(person.name);
person.name = "";
console.log(person.name);

通过get/set属性来修改私有属性可以做到拦截/判断的作用

静态成员

静态成员通过 static 关键字来定义,通过 static 定义的属性,是定义在类自身的,只能通过自己访问,在类内部和实例对象都是无法访问到的。

抽象类

在定义很多通用的调用接口时,我们通常会让调用者传入父类,通过多态来实现更加灵活的调用方式。

但是,父类本身可能并不需要对某些方法进行具体的实现,所以父类中定义的方法, 我们可以定义为抽象方法。

abstract class Shape {
  abstract getArea(): void;
}
class Circle extends Shape {
  private radius: number;
  constructor(radius: number) {
    super();
    this.radius = radius;
  }
  getArea() {
    return this.radius * this.radius * 3.14;
  }
}
class Rectangle extends Shape {
  private width: number;
  private height: number;
  constructor(width: number, height: number) {
    super();
    this.width = width;
    this.height = height;
  }
  getArea() {
    return this.width * this.height;
  }
}
function calcArea(shape: Shape) {
  return shape.getArea();
}
console.log(calcArea(new Circle(3)));
console.log(calcArea(new Rectangle(2, 6)));

抽象方法和方法通过 abstract 来修饰,并且抽象类定义时有两条规则:

  • 抽象方法必须要在子类实现
  • 抽象类是不能被实例化的

类的类型

类本身也是可以作为一种数据类型的,可以用作类型注解。

class Person {
  name: string = "alice";
  eating() {}
}
const person: Person = {
  name: "kiki",
  eating() {
    console.log("i am eating");
  },
};
function printPerson(person: Person) {
  console.log(person.name);
}
printPerson(new Person());
printPerson(person);
printPerson({ name: "macsu", eating() {} });

只要符合类的格式,就可以使用类的类型

函数和类在JS和TS中都是至关重要的,可以帮助开发者更好规范开发时的代码,减少线上故障~

总结

以上就是关于TypeScript函数和类的内容,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • TypeScript常见类型及应用示例讲解

    目录 常见类型(Everyday Types) 原始类型: 数组(Array) any noImplicitAny 变量上的类型注解(Type Annotations on Variables) 函数(Function) 参数类型注解(Parameter Type Annotations) 返回值类型注解(Return Type Annotations) 匿名函数(Anonymous Functions) 对象类型(Object Types) 可选属性(Optional Properties)

  • TypeScript中函数重载写法

    目录 1. 函数签名 2.函数重载 2.1 重载签名是可调用的 2.1 实现签名必须是通用的 3.方法重载 4. 何时使用函数重载 5.总结 前言: 大多数函数接受一组固定的参数.但有些函数可以接受可变数量的参数,不同类型的参数,甚至可以根据你调用函数的方式返回不同的类型.为了注释这样的函数,TypeScript 提供了函数重载功能. 1. 函数签名 我们先来考虑一个函数,它返回给一个特定的人的问候信息. function greet(person: string): string { retu

  • TypeScript中的类

    目录 1.概述 2.定义一个简单的类 3.继承 4.public.private.protected修饰符 4.1getters与setters 5.readonly修饰符 6.静态成员 7.抽象类 8.类与接口 1.概述 类这个概念基本是所有面向对象编程语言都具有一个概念,例如Java.Python等:在JavaScript中ES6 之前是没有类这个概念的,对于熟悉面向对象来程序猿来说有些棘手,因为他们用的都是基于类的继承,对象也是通过类创建出来的.在ES6中添加了类这个概念,虽然只是一个语法

  • TypeScript的函数定义与使用案例教程

    TypeScript中函数的定义和使用 1. 声明一个函数约束其传参类型,以及返回值类型 传入两个参数,没有返回值 const fun1 = (key: string, value: number): void => { console.log(key, value);//"Typescript",100 }; fun1("Typescript", 100); 2.TypeScript中的函数配置可选参数,在ES5或者ES6中函数中的实参可以不传递进去,但是在

  • TypeScript中的函数

    目录 1.函数定义 1.1JavaScript中的函数 1.2TypeScript中的函数 3.可选参数和默认参数 4.剩余参数 1.函数定义 1.1JavaScript中的函数 在学习TypeScript中的函数前我们先来回顾一下JavaScript中的函数定义常用的包含以下几种: 第一种:使用function关键字声明函数 function add1 (x, y) { return x + y } 第二种:使用字面量方式声明函数 const add2 = function (x, y) {

  • TypeScript中的函数和类你了解吗

    目录 函数 作为参数 定义函数 函数参数的类型 可选类型 参数默认值 剩余参数 this的默认推导 函数重载 类 初始化 继承 多态 成员修饰符 总结 函数 以下声明了一个函数类型,通过type来定义类型别名,void 表示没有返回值 type fnType = () => void; 作为参数 函数可以作为参数,传递到另一个函数中 type fnType = () => void; function foo(fn: fnType) { fn(); } function bar() { con

  • 简单了解TypeScript中如何继承 Error 类

    前言 在JavaScript 中很多时候都需要自定义错误,尤其是开发 Node.js 应用的时候. 比如一个典型的网站服务器可能需要有 NetworkError, DatabaseError, UnauthorizedError 等. 我们希望这些类都拥有 Error 的特性:有错误消息.有调用栈.有方便打印的 toString 等. 最直观的实现方式便是 继承 Error 类. 但考虑 TypeScript 需要编译到 ES5 兼容性问题会较为复杂, 本文用来帮助理解 TypeScript 中

  • TypeScript 泛型重载函数的使用方式

    目录 前言 TypeScript 的运行环境 1. ts-node 2. tsc TypeScript 中的函数重载 简单的排序算法 1. 快速排序 2. 中文排序 3. 字符串自排序 4. 通过泛型整合几种排序 5. 使用函数重载完善排序功能 总结 前言 使用 TypeScript 进行开发也已经有段日子了,虽然最开始接触后以为这不就和 Java 一样一样的么,然而越深入了解越发现还真不一样~不过有些概念来说是相通的,比如泛型. Java 里也有函数重载,但是和 TS 差别还是挺大的,那就通过

  • python利用dir函数查看类中所有成员函数示例代码

    前言 如果一个类是别人编写的,又没有帮助文档,怎么样来查看所有成员函数呢?本文详细给大家介绍了关于python用dir函数查看类中所有成员函数的相关内容,下面话不多说了,来一起看看详细的介绍吧. 可以使用下面的代码: # File: builtin-dir-example-2.py class A: def a(self): pass def b(self): pass class B(A): def c(self): pass def d(self): pass def getmembers(

  • 解析VC中创建DLL,导出全局变量,函数和类的深入分析

    一.创建DLL1.在VC中新建一个Win32空项目MathLib:2.添加预编译头文件stdafx.h,定义导入导出控制符号: 复制代码 代码如下: //stdafx.h#pragma once#define MATHLIB_EXPORT 3.添加包含要导出的全局变量,函数和类的头文件MathLib.h: 复制代码 代码如下: //MathLib.h #pragma once #ifdef MATHLIB_EXPORT #define MATHLIBAPI __declspec(dllexpor

  • C++ 中友元函数与友元类详解

    C++ 中友元函数与友元类详解 总的来说,友元分为两类:友元函数与友元类.友元是针对类而言,它提供了一种非类的成员函数来访问类的非公有成员的一种机制.可以把一个函数指定为某类的友元,这个函数称为这个类的友元函数.也可以将类A指定为类B的友元,则类A是类B的友元类,类A的所有成员函数均是类B的友元函数,均可以访问类B的非公有成员.        友元函数的注意事项: (1)友元函数不是类的成员函数,在函数体中访问对象的成员,必须用"对象名.对象成员"方式来访问, 友元函数可以访问类中的所

  • 对python中不同模块(函数、类、变量)的调用详解

    首先,先介绍两种引入模块的方法. 法一:将整个文件引入 import 文件名 文件名.函数名( ) / 文件名.类名 通过这个方法可以运行另外一个文件里的函数 法二:只引入某个文件中一个类/函数/变量 需要从某个文件中引入多个函数或变量时,用逗号隔开即可 from 文件名 import 函数名,类名,变量名 接下来,通过一个具体的例子说明引入 模块的具体方法: 假设新建一个python包test2,里边有一个名为run.py的python文件,run.py文件里有一个名为running()的函数

随机推荐