Typescript 的 class 类

news2024/11/15 10:51:45

介绍

1. 类介绍

传统的JavaScript通过函数和基于原型的继承来创建可重用的组件,从ES6开始,JavaScript程序员也可以使用面向对象的方法来创建对象。例如,下列通过class关键词,来声明了一个类:Greeter

class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}

通过使用new Greeter()可以创建很多个基于该Greeter类的实例。如let greeter = new Greeter("world");,就创建了一个该类的实例greeter。

2. 类继承

在基于类的程序设计中,一种最基本的模式是:允许通过继承来实现类的扩展。如下面的例子,我们首先定义了一个Animal的类,然后又定义了Dog类并扩展了Animal,此时通过Dog类创建的实例就自动继承了Animal中的方法和属性:

class Animal {
    move(distanceInMeters) {
        console.log(`Animal moved ${distanceInMeters}m.`)
    }
}

class Dog extends Animal {
    bark() {
        console.log('Woof! Woof!')
    }
}

const dog = new Dog()
dog.bark() // Woof! Woof!
dog.move(10) // Animal moved 10m.
dog.bark() // Woof! Woof!

Typescript的继承中一个最重要的关键字:super。例如下面的例子,我们首先定义了Animal类,然后使用extends关键词创建了Animal的两个子类:HorseSnake

class Animal {
    name: string
    constructor(theName: string) {
        this.name = theName
    }
    move(distanceInMeters: number = 0) {
        console.log(`${this.name} moved ${distanceInMeters}m.`)
    }
}
class Snake extends Animal {
    constructor(name: string) {
        super(name)
    }
    move(distanceInMeters = 5) {
        console.log('Slithering...')
        super.move(distanceInMeters)
    }
}
class Horse extends Animal {
    constructor(name: string) {
        super(name)
    }
    move(distanceInMeters = 45) {
        console.log('Galloping...')
        super.move(distanceInMeters)
    }
}

let sam = new Snake('Sammy the Python')
let tom: Animal = new Horse('Tommy the Palomino')

sam.move() // Slithering... Sammy the Python moved 5m.
tom.move(34) // Galloping... Tommy the Palomino moved 34m.

与前面不同的是:

  1. 派生类Snake和Horse都包含了一个构造函数,它必须调用super才行,它会执行基类里的构造函数。而且在构造函数里访问this属性之前,也一定要调用super——这是typescript强制执行的一条重要原则
  2. 该示例演示了如何重写父类的方法:Snake和Horse都创建了move方法,它们重写了冲Animal继承来的move方法,使得move在不同的类里有不同的功能。注意:即使tom被声明为Animal类,但因为它的值被声明为了Horse,调用.move方法时,还是执行的Horse里面的方法。

所以,上述方法中,调用sam.move()tom.move(34)的输出分别为:

sam.move()
// Slithering... 
// Sammy the Python moved 5m.

tom.move(34)
// Galloping... 
// Tommy the Palomino moved 34m.

这是Typescript里面关于类的一个高级用法,在创建一些复杂类的时候可能会使用到,需要掌握。

3. 修饰符

3.1 public(默认)

在Typescript里,成员默认都是public,不过你开业可以将一个成员标记成明确的public类。如下面的示例:

class Animal {
    public name: string
    public constructor(theName: string) {
        this.name = theName
    }
    public move(distanceInMeters: number = 0) {
        console.log(`${this.name} moved ${distanceInMeters}m.`)
    }
}

将Animal类里的属性全都标记成public,与前面不标记时的结果一样。

3.2 private

当成员被声明为private,它就不能被声明它的函数的外部访问。如:将Animal类中的name声明为private

class Animal {
    private name: string
    public constructor(theName: string) {
        this.name = theName
    }
}

使用new Animal("Cat").name方法访问name就会报错,错误为:提示name是私有化属性。

3.3 protected

protectedprivate修饰符优点相似,不同的是:protected修饰符在派生类中也可以访问。如下图中,当我们在Person类中定义了protected类型的属性,在派生的howard示例中访问name,就会提示该属性是protectd无法被访问,而访问private类型的department则无提醒。
在这里插入图片描述
另外,构造函数也可以被声明为protected,这意味着这个类不能在包含它的类外被实例化,但是能被继承。

3.4 readonly

只读属性,必须在声明时或构造函数里被初始化。如:我们定义了readonly属性,就无法在实例里面赋值。
在这里插入图片描述

4. 存取器

存取器指的就是typescript的get/set方法,它可以方便我们修改类中的属性。如,下列代码定义了一个修改名称的方法,在修改名称时还验证了passcode是否正确,如果正确则修改成功,否则不做修改。

let passcode = 'secert passcode'
class Employee {
    private _fullName: string

    get fullName(): string {
        return this._fullName
    }

    set fullName(newName: string) {
        if(passcode && passcode === 'secert passcode') {
            this._fullName = newName
        } else {
            console.log('Error: Unauthorized update of employee')
        }
    }
}

当我们创建一个基于Employee的实例,并且对它修改名称和获取名称:

let employee = new Employee()
employee.fullName = 'Bolb Smith'
if(employee.fullName) {
    alert(employee.fullName)
}

需要注意:

  • 存取器要求将编译器设置为输出ECMAScript 5或更高
  • 只带有get不带有set的存取器自动被推断为readonly
  • 使用存取器在从代码生成.d.ts文件时是有帮助的,因为利用这个属性的用户会看到不允许够改变它的值。

5. 静态属性

typescript除了可以定义实例属性,还可以定义静态属性。静态属性存在于类本身上面而不是类的实例上,如在下面的例子中,在我们使用static定义origin,因为它是所有网格都会用到的属性。 每个实例想要访问这个属性的时候,都要在origin前面加上类名。 如同在实例属性上使用this.前缀来访问属性一样,这里我们使用Grid.来访问静态属性。

class Grid {
    static origin = { x: 0, y: 0 }
    calculateDistanceFromOrigin(point: {x: number, y: number}) {
        let xDist = (point.x - Grid.origin.x)
        let yDist = (point.y - Grid.origin.y)
        return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale
    }
    constructor(public scale: number) {}
}

let grid1 = new Grid(1.0) // 1x scale
let grid2 = new Grid(5.0) // 5x scale

console.log(grid1.calculateDistanceFromOrigin({x:10, y: 10}))
console.log(grid2.calculateDistanceFromOrigin({x:10, y: 10}))

6. 抽象类

抽象类通过关键词abstract来定义。抽象类中的抽象方法不包含具体实现而且必须在派生类中实现。如下列的代码,我们定义了一个抽象类,并且在派生中实现了抽象类中的方法:
在这里插入图片描述
可以看到:

  • 如果要继承抽象类,则抽象类中定义的方法一定要在实例中实现
  • 不能直接创建一个抽象类的实例
  • 声明成抽象类的实例,无法使用实例中的方法

高级技巧

1. 构造函数

在TypeScript里声明一个类的时候,实际上同时声明了很多东西。 首先就是类的实例的类型,如我们可以写let greeter: Greeter,这其实就是说Greeter类的实例的类型是Greeter。这个其实很好懂,了解JavaScript中的原型继承就能很好理解这个概念。

2. 把类当接口使用

如前所述,类定义会创建两个东西:类的实例类型和一个构造函数。 因为类可以创建出类型,所以你能够在允许使用接口的地方使用类。

class Point {
    x: number
    y: number
}

interface Point3d extends Point {
    z: number
}

let point3d: Point3d = { x: 1, y: 2, z: 3 }

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

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

相关文章

shell 脚本 批量 修改 文件名

shell 脚本 批量 修改 文件名 原始文件 你可以使用以下的shell脚本来批量修改文件名: #!/bin/bashinput_dir$1if [ -z "$input_dir" ]; thenecho "Usage: ./rename.sh input_directory"exit 1 ficd "$input_dir" || exitfor file in…

C百题--6.输出C

1.问题描述 输出“C”样式的字符 2.解决思路 1.用printf(&#xff09;逐行输出&#xff1b; 2用循环一部分一部分输出 3.代码实现 #include<stdio.h> int main(){for(int i0;i<5;i){printf("*"); }printf("\n");for(int i0;i<2;i){printf…

【保姆级教程】协同双注意力机制CDAM2与YOLOv7结合:构建高效工地头盔检测系统

1.研究的背景和意义 随着工业化和城市化的快速发展&#xff0c;建筑工地的安全问题日益凸显。在建筑工地中&#xff0c;工人的安全是至关重要的&#xff0c;而工地安全帽的佩戴是保障工人安全的重要措施之一。然而&#xff0c;由于工地环境复杂多变&#xff0c;工人的佩戴情况…

OpenStack云计算平台-启动一个实例

目录 一、创建虚拟网络 ​二、创建m1.nano规格的主机 三、生成一个键值对 四、增加安全组规则 ​五、启动一个实例 1、确定实例选项 2、创建实例 3、使用虚拟控制台访问实例 4、验证能否远程访问实例 一、创建虚拟网络 下面的说明和框图使用示例IP 地址范围。你必须依…

[Linux] shell脚本的函数和数组

一、函数 1.1 函数的定义 函数是脚本的别名 作用&#xff1a;函数可以避免代码重复&#xff0c;可读性强&#xff0c;可以简化脚本。 格式&#xff1a;函数名&#xff08;&#xff09;{脚本} 1.2 如何使用函数 1.定义 2.调用 函数一定要先定义再使用 例子&#xff1a…

Linux 的性能调优的思路

Linux操作系统是一个开源产品&#xff0c;也是一个开源软件的实践和应用平台&#xff0c;在这个平台下有无数的开源软件支撑&#xff0c;我们常见的apache、tomcat、mysql等。 开源软件的最大理念是自由、开放&#xff0c;那么Linux作为一个开源平台&#xff0c;最终要实现的是…

为企业解决设备全生命周期需求,凌雄科技凸显DaaS增长价值

企业成长离不开投资&#xff0c;但毫无疑问的是&#xff0c;投资最有价值的部分在业务。相比之下&#xff0c;诸如办公设备之类的固定资产投资&#xff0c;很容易变成企业现金流的吞噬者。从购买、运维到保养、折旧、回收&#xff0c;现代企业在越来越大的办公设备规模面前&…

通过Whisper模型将YouTube播放列表中的视频转换成高质量文字稿的项目

项目简介 一个通过Whisper模型将YouTube播放列表中的视频转换成高质量文字稿的项目。 这个基于 Python 的工具旨在将 YouTube 视频和播放列表转录为文本。它集成了多种技术&#xff0c;例如用于转录的 Fast-Whisper、用于自然语言处理的 SpaCy 以及用于 GPU 加速的 CUDA&…

机器学习实战-第5章 Logistic回归

Logistic 回归 概述 Logistic 回归 或者叫逻辑回归 虽然名字有回归,但是它是用来做分类的。其主要思想是: 根据现有数据对分类边界线(Decision Boundary)建立回归公式,以此进行分类。 须知概念 Sigmoid 函数 回归 概念 假设现在有一些数据点,我们用一条直线对这些点进行…

Redis深入理解-内核请求处理流程、数据传输协议

Redis 内核级请求处理流程 Redis Server 其实就是 Linux 服务器中的一个进程 主要还是下图的流程 应用先和 server 端建立 TCP 连接建立连接之后&#xff0c;server 端就会有一个与该客户端通信的 socket&#xff0c;客户端的读写请求发送到服务端的 socket那么通过 IO 多路…

C百题--3.求未知数

1.问题描述 一个正整数&#xff0c;它加上100后是一个完全平方数&#xff0c;再加上168又是一个完全平方数&#xff0c;请问该数是多少&#xff1f; 2.解决思路 遍历这个数&#xff0c;让其从1开始&#xff0c;到100000结束 3.代码实现 #include<stdio.h> #include&…

【操作系统】Bochs安装和配置

Bochs是使用C编写的高度可移植开源IA-32&#xff08;X86&#xff09;PC模拟器&#xff0c;能在大多数流行的平台上运行。它包括模拟Intel x86 CPU、常见I/O设备和自定义BIOS。Bochs可以被编译以模拟许多不同的x86 CPU&#xff0c;从386早期到最新的x86-64英特尔和AMD处理器甚至…

区间第k小数 (可持久化线段树、主席树)

题意&#xff1a;多次询问&#xff0c;每次询问某区间的第k小数。 可持久化线段树&#xff1a; 掺杂了一点前缀和的思想&#xff0c;对于每一个1 ~ i 的区间都建一个树&#xff0c;每个节点存的都是一个线段树&#xff0c;值存的是当前区间中初始数组按大小排序后[l, r]之间的…

Shopee本土号封号几率大吗?如何避免封号?被封号了怎么办?

Shopee是近几年热门的电商平台之一&#xff0c;即使越来越多的跨境电商涌现&#xff0c;他的地位在东南亚市场依然占据一席之地&#xff0c;也依旧吸引着需要跨境商家入局。尤其在2023年&#xff0c;在TikTok Shop在印尼被关停之后&#xff0c;留下了大片空白&#xff0c;Shope…

如何解决tinder注册失败的问题?

tinder创立在2012年&#xff0c;是一款海外热门的交友软件。2020年&#xff0c;Tinder拥有620万用户和7500万月活跃用户。截至2021年&#xff0c;Tinder在全球范围内的匹配记录超过650亿。已成为全球最受欢迎的约会软件之一。 目前tinder暂时未对中国大陆开发使用&#xff0c;…

Python入门教程 | Python3 字典(dict)

Python3 字典 字典是另一种可变容器模型&#xff0c;且可存储任意类型对象。 Python3中的字典是一种无序、可变、可迭代的数据结构&#xff0c;它由键&#xff08;key&#xff09;和对应的值&#xff08;value&#xff09;组成。字典在Python中被视为可变对象&#xff0c;这意…

多级缓存快速上手

哈喽~大家好&#xff0c;这篇来看看多级缓存。 &#x1f947;个人主页&#xff1a;个人主页​​​​​ &#x1f948; 系列专栏&#xff1a;【微服务】 &#x1f949;与这篇相关的文章&#xff1a; JAVA进程和线程JAVA进程和线程-CSDN博客Http…

【数据结构/C++】栈和队列_链队列

#include <iostream> using namespace std; // 链队列 typedef int ElemType; typedef struct LinkNode {ElemType data;struct LinkNode *next; } LinkNode; typedef struct {LinkNode *front, *rear; } LinkQueue; // 初始化 void InitQueue(LinkQueue &Q) {Q.fron…

Redis深入理解-Socket连接建立流程以及文件事件处理机制

Redis Server 运行原理图 Redis 服务器中 Socket 网络建立以及文件事件模型 一个 redis 单机&#xff0c;可以抗几百上千的并发&#xff0c;这里的并发指的就是同时可以有几百个 client 对这个 redis server 发起请求&#xff0c;都需要去建立网络连接&#xff0c;同时间可能会…

Attention is All You Need:Transformer各模块详解

Transformer encoder-decoder架构 Encoder&#xff1a;将输入序列转换为一个连续向量空间中的表示。Encoder通常是一个循环神经网络&#xff08;RNN&#xff09;或者卷积神经网络&#xff08;CNN&#xff09;&#xff0c;通过对输入序列中的每个元素进行编码&#xff0c;得到…