typescript学习回顾(四)

news2024/12/26 21:27:26

今天来分享下ts中的类,关于ts中的类的概念,面向对象的一种思想,以及类里面的一些属性成员,一些基础的用法,后面会有一个小练习。

基本概念

我的理解:类是编程语言中面向对象的一种思想,一个类是抽象事物的一个集合,比如人可以是一个类,类的实例对象具体到某一个人,所以这两者之间从抽象到具体。

面向对象思想

关于面向对象的一个思想的好处,可以让我们在开发的过程中,更易于维护我们的代码,以及我们的对象实例每个都是独立出来的,每次创建一个对象,都是NEW一个实例,每个实例之间互相不影响。面向对象用来编写模块化的代码也是非常的友好,而且公共类可以抽成接口用来继承,对于开发来说可以更加的清晰,逻辑更加的明确,同样对于灵活性和可扩展性也是有保障的。

  • 代码重用性
  • 代码可维护性

以前传统js类写法

es5
function User(userobj){
    this.name = userobj.name;
    this.age = userobj.age;
    this.sex = userobj.sex;
    this.phone = userobj.phone;
    this.address = userobj.address;
}

const u = new User({
    name : 'kakarote',
    age : 18,
    sex : "男",
    phone : "1008611",
    address : "广东深圳宝安区"
});

console.log(u)
es6
class User{
    constructor(userobj){
        this.name = userobj.name;
        this.age = userobj.age;
        this.sex = userobj.sex;
        this.phone = userobj.phone;
        this.address = userobj.address;
    }
}

const u = new User({
    name: 'kakarote',
    age: 18,
    sex: "男",
    phone: "1008611",
    address: "广东深圳宝安区"
});

console.log(u)

打印结果:

在这里插入图片描述

ts编写类

class User {
    constructor(name: string, age: number,sex:string,phone:string,address:string) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.phone = phone;
        this.address = address;
    }
}

在这里插入图片描述

在ts中如果按照上面这种写法是会报错的,ts觉得这种写法不太好,如果我们写一个类,我们应该是清楚这个类里面到底有哪些属性的,创建属性里面的工作不允许放在构造函数里面写。因为如果可以添加的话就可能会造成很多有隐患的代码,最后可能都不清楚这个对象到底是有哪些属性,ts认为属性是不能添加的,必须提前限制好。

ts让我们使用属性列表来描述类里面的属性

列表直接写到class里面

class User {
    name: string
    age: number
    sex: string
    phone: string
    address: string

    constructor(name: string, age: number, sex: string, phone: string, address: string) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.phone = phone;
        this.address = address;
    }
}

编译结果里面不会带这个属性列表

不能随意添加属性

比如下图我想给这个u实例添加一个id,这个在ts中是不允许的

在这里插入图片描述

更加严格的属性初始化

但是可能会有下面这种情况,我没有构造函数,但是我直接创建user实例也不会报错,但是这样user对象的每个属性都是undefined,就和类型不符合了

class User {
    name: string
    age: number
    sex: string
    phone: string
    address: string
}

const u = new User();

或者说,我写了构造函数,但是有些在构造函数里没赋值,希望ts能够提示出来,这样怎么做呢

这里可以在tsconfig.json里面加上一个配置,这个属性为strictPropertyInitialization

{
  "compilerOptions": { //编译选项
     "strictPropertyInitialization": true //这样ts会对类里面的属性初始化进行严格校验
  },
 
}

strictPropertyInitialization

这个属性它会监测

  • 构造函数中是否赋值
  • 是否存在属性默认值

设置默认值

这里一般性别都是男或者女,这里我希望能有个默认值

enum Sex{
    Male = "男",
    Female = '女'
}

class User {
    name: string
    age: number
    sex: Sex = Sex.Male //设置默认值
    phone: string
    address: string
	
    //这样可以少传递一个参数
    constructor(name: string, age: number phone: string, address: string) {
        this.name = name;
        this.age = age;
        this.phone = phone;
        this.address = address;
    }
}

const u = new User(...具体参数);
u.sex = Sex.Female;

可选

类里面有些属性,我希望是可选的,那在ts中怎么写呢?

class User {
    name: string
    age: number
    sex: Sex = Sex.Male //设置默认值
    phone?: string //可以在:前面加个?这样就代表这个属性是可选的,可以传递也可以不传递
}

只读属性

在有些场景下,我们希望这个类的属性是只读属性,不能改的,比如说id属性,一般来说id都是自动生成的不可以改的,这里我们可以在属性前面加上readonly关键字

class User {
	readonly id:number
    name: string
    age: number
    sex: Sex = Sex.Male //设置默认值
    phone?: string //可以在:前面加个?这样就代表这个属性是可选的,可以传递也可以不传递
    
    constructor(){
        ///...
        
        //举例子
        this.id = new Date().getTime();
    }
}

使用访问修饰符

访问修饰符可以控制类中的某个成员的访问权限

  • public:默认的访问修饰符,公开的,所有代码均可以访问
  • private: 私有的,只有在类中可以访问
  • protected
class User {
    //...
    //设置私有的两个属性
    private _publishNumber: number = 3 //每天一共可以发布多少篇文章
    private _curNumber: number = 0; //当前文章发布数量

    publish(title: string) {
        if (this._curNumber < this._publishNumber) {
            console.log("发布了一篇文章" + title);
            this._curNumber++;
        } else {
            console.log("你今日发布的文章数量已达到上限")
        }
    }
}


const u = new User("aa", 22);

u.publish('文章1')
u.publish('文章2')
u.publish('文章3')
u.publish('文章4')

在这里插入图片描述

Tips:开发的原则,尽量少的暴露公共的属性,暴露出来的成员容易被其他开发者直接修改,容易造成很多隐患,所以一般都是暴露出一些需要用的函数和属性,一些不需要用的属性尽量私有化。

属性简写

如果某个属性,通过构造函数的参数传递,并且不做任何处理的赋值给该属性。可以进行简写

class User {
    sex: Sex = Sex.Male //设置默认值
    phone?: string //可以在:前面加个?这样就代表这个属性是可选的,可以传递也可以不传递

    constructor(public name: string, public age: number) {

    }
}

const u = new User('kakarote',11);

console.log(u)

前提是这里必须加上修饰符,不加修饰符是无效的

在这里插入图片描述

访问器

有些属性我们不希望直接对他进行赋值,以及直接进行读取,这样可能会存在一些问题,这里就需要用到访问器的知识

class User{
    //设置私有化_age变量
    constructor(public name: string, private _age: number) {
    }

    setAge(value: number) {
        if(value < 0){
            this._age = 0;
        }else if(value >= 200){
            this._age = 200;
        }else{
            this._age = value;
        }
    }

    getAge() {
        return Math.floor(this._age);
    }
}

const u = new User("aa", 22);
console.log(u.getAge())
u.setAge(11)
console.log(u.getAge())

我们可以使用这种函数的形式,这样就可以实现一个访问器的效果,但是js的类里面给我们提供了get和set的一个关键字,这个关键字可以达到一样的效果,而且还可以让我们用传统的赋值和读取的写法。它的本质还是一个函数,有点类似Object.defineProperty的存取器

class User{
    //设置私有化_age变量
    constructor(public name: string, private _age: number) {
    }

    set age(value: number) {
        if(value < 0){
            this._age = 0;
        }else if(value >= 200){
            this._age = 200;
        }else{
            this._age = value;
        }
    }

    get age() {
        return Math.floor(this._age);
    }
}

const u = new User("aa", 22);
console.log(u.age)
u.age = 11;
console.log(u.age)
 

在这里插入图片描述

这个完全是可以达到一样的效果的

小练习

我们上期typescript回顾二里面分享了扑克牌的功能,现在希望使用ts的类对它进行一个改造

1. 目标:创建一幅扑克牌(不包括大小王),打印该扑克牌,增加洗牌和发牌功能

2. 使用枚举改造程序

3. 使用模块化

4. 用接口改造程序,加入大小王

5. 用类改造程序
目录结构
  • src
    • deck.ts
    • enum.ts
    • index.ts
    • types.ts
enum.ts

定义枚举,形状以及标记

export enum Shape {
    heart = "♥",
    spade = "♠",
    club = "♣",
    diamond = "♦",
}

export enum Mark {
    A = "A",
    two = "2",
    three = "3",
    four = "4",
    five = "5",
    six = "6",
    seven = "7",
    eight = "8",
    nine = "9",
    ten = "10",
    eleven = "J",
    twelve = "Q",
    king = "K"
}
type.ts

用来定义类型,普通牌的一个类型定义

import { Color, Mark } from "./enums";

//一副牌是个Card数组
export type Deck = Card[];

//定义每张牌
export interface Card {
    getString(): string
}

//普通牌
export interface NormalCard extends Card {
    color: Color,
    mark: Mark,
}

//大小王
export interface Joker extends Card {
    type: "big" | "small"
}
deck.ts

//用于定义具体的一个扑克牌游戏规则

import { Mark, Color } from "./enums";
import { Card, Joker } from "./types";

//发牌对象,每个玩家发xx张牌
interface PublishResult {
    player1: Deck,
    player2: Deck,
    player3: Deck,
    left: Deck
}

export class Deck {
    private cards: Card[] = [];

    constructor(cards?: Card[]) {
        if (cards) {
            this.cards = cards;
        } else {
            this.init();
        }
    }
	
    //初始化
    private init() {
        const marks = Object.values(Mark);
        const colors = Object.values(Color);
        for (const m of marks) {
            for (const c of colors) {
                this.cards.push({
                    mark: m,
                    color: c,
                    getString() {
                        return this.color + this.mark;
                    }
                } as Card);
            }
        }

        let joker: Joker = {
            type: "small",
            getString() {
                return "jo"
            },
        }
        this.cards.push(joker);
        joker = {
            type: "big",
            getString() {
                return "Jo"
            },
        }
        this.cards.push(joker);
    }

    print() {
        let result = "\n";
        this.cards.forEach((card, i) => {
            result += card.getString() + "\t";
            if ((i + 1) % 6 === 0) {
                result += "\n";
            }
        });
        console.log(result)
    }

    /**
     * 洗牌
     */
    shuffle() {
        //[x1,x2,x3,x4,x5,x6,x7]
        for (let i = 0; i < this.cards.length; i++) {
            const targetIndex = this.getRandom(0, this.cards.length);
            const temp = this.cards[i];
            this.cards[i] = this.cards[targetIndex];
            this.cards[targetIndex] = temp;
        }
    }

    // 发完牌后,得到的结果有4个card[]
    publish(): PublishResult {
        let player1: Deck, player2: Deck, player3: Deck, left: Deck;
        player1 = this.takeCards(17);
        player2 = this.takeCards(17);
        player3 = this.takeCards(17);
        left = new Deck(this.cards);


        return {
            player1,
            player2,
            player3,
            left
        };
    }

    private takeCards(n: number): Deck {
        const cards: Card[] = [];

        for (let i = 0; i < n; i++) {
            cards.push(this.cards.shift() as Card);
        }
        return new Deck(cards);
    }

    /**
     * 无法取到最大值
     * @param min 
     * @param max 
     * @returns 
     */
    private getRandom(min: number, max: number) {
        const dec = max - min;
        return Math.floor(Math.random() * dec + min)
    }
}
index.ts

入口,引入扑克牌游戏

import { Deck } from "./deck";

const deck = new Deck();
deck.shuffle();
console.log("===========洗牌之后===========")
deck.print();

const result = deck.publish();
console.log("===========发牌之后===========");

console.log("===========玩家1===========");
result.player1.print();

console.log("===========玩家2===========");
result.player2.print();

console.log("===========玩家3===========");
result.player3.print();

console.log("===========玩家3===========");
result.player3.print();

console.log("===========地主牌===========");
result.left.print();

在这里插入图片描述

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

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

相关文章

flutter是app跨平台最优解吗?

哈喽&#xff0c;我是老刘 最近在知乎上看到这样一个问题 我们先来解释一下问题中碰到的几个现象的可能原因&#xff0c;然后聊聊跨平台的最优解问题 问题解释 1、跟手、丝滑问题 这个问题其实很多人是有误解的&#xff0c;觉得原生的就丝滑跟手 其实不是这样的 我在做Flut…

【内网安全】组策略同步-不出网隧道上线-TCP转ICMP

目录 域控-防火墙-组策略对象同步演示1、打开组策略管理&#xff0c;新建一个GPO连接 取名fhq(防火墙)2、编辑fhq并设置防火墙状态3、命令&#xff1a;gpupdate/force 更新策略4、域控主机新增规则5、域内用户主机更新规则 域控-防火墙-组策略不出网上线演示 ICMP协议上线&…

CentOS停更无忧,中国操作系统闯入后CentOS时代

国际开源服务器操作系统CentOS停更&#xff0c;引发了中国操作系统火线进化——开源龙蜥操作系统社区涌现出大量的技术创新&#xff0c;相关创新技术迅速转化为商业化产品。2024年6月&#xff0c;浪潮信息与龙蜥社区联合发布服务器操作系统云峦KeyarchOS V5.8 新版本&#xff0…

【秋招突围】2024届秋招笔试-科大笔试题-01-三语言题解(Java/Cpp/Python)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系计划跟新各公司春秋招的笔试题 &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f497; 文章目录 &#x1f4d6…

入门网络安全工程师要学习哪些内容

大家都知道网络安全行业很火&#xff0c;这个行业因为国家政策趋势正在大力发展&#xff0c;大有可为!但很多人对网络安全工程师还是不了解&#xff0c;不知道网络安全工程师需要学什么?知了堂小编总结出以下要点。 网络安全工程师是一个概称&#xff0c;学习的东西很多&…

六、资产安全—信息分级资产管理与隐私保护(CISSP)

目录 1.信息分级 2.信息分级方法 3.责任的层级 4.资产管理 5.隐私数据管理角色 6.数据安全控制 7.数据保护方案 8.使用安全基线 六、资产安全—数据管理(CISSP): 五、身份与访问管理—身份管理和访问控制管理(CISSP): 1.信息分级 信息分级举列: 2.信息分级方…

ingress相关yaml文件报错且相关资源一切正常解决方法

今天在执行ingress相关文件的时候莫名其妙报错了&#xff0c;问了别人得知了这个方法 执行ingress相关文件报错 01.yaml是我自己创建关于ingress的yaml文件 报错信息 且相关资源一切正常 解决方法 kubectl get validatingwebhookconfigurations删除ingress-nginx-admissio…

商城积分系统的代码实现(上)-- 积分账户及收支记录

一、背景 上一系列文章&#xff0c;我们说了积分的数模设计及接口设计&#xff0c;接下里&#xff0c;我们将梳理一下具体的代码实现。 使用的语言的java&#xff0c;基本框架是spring-boot&#xff0c;持久化框架则是Jpa。 使用到的技术点有&#xff1a; 分布式锁&#xf…

AI大模型日报#0628:谷歌开源9B 27B版Gemma2、AI首次实时生成视频、讯飞星火4.0发布

导读&#xff1a;AI大模型日报&#xff0c;爬虫LLM自动生成&#xff0c;一文览尽每日AI大模型要点资讯&#xff01;目前采用“文心一言”&#xff08;ERNIE-4.0-8K-latest&#xff09;生成了今日要点以及每条资讯的摘要。欢迎阅读&#xff01;《AI大模型日报》今日要点&#xf…

抗击.michevol勒索病毒:保障数据安全的新策略

导言&#xff1a; 在今天高度互联的数字化环境中&#xff0c;数据安全面临着越来越复杂和普遍的威胁&#xff0c;勒索病毒如.michevol已成为了用户和企业普遍面临的风险。本文91数据恢复将探讨.michevol勒索病毒的特点、感染方式以及创新的防御策略&#xff0c;旨在帮助读者更…

九、(正点原子)Linux定时器

一、Linux中断简介 1、中断号 每个中断都有一个中断号&#xff0c;通过中断号即可区分不同的中断&#xff0c;有的资料也把中断号叫做中断线。在 Linux 内核中使用一个 int 变量表示中断号。在Linux中&#xff0c;我们可以使用已经编写好的API函数来申请中断号&#xff0c;定义…

快手主播李香周助力推动 K-beauty风潮谈背后成功秘诀

近年来&#xff0c;互联网的迅速发展和SNS社交媒体的普及&#xff0c;人们通过网络可以随时随地对自己感兴趣的自由畅谈和学习。而直播带货更是作为一种依托于互联网兴起的新型营销方式&#xff0c;凭借其价格优势和新颖的介绍方式为消费者带来了十分便捷的购物体验。 本期采访…

【shell脚本速成】python安装脚本

文章目录 案例需求应用场景解决问题脚本思路案例代码 &#x1f308;你好呀&#xff01;我是 山顶风景独好 &#x1f388;欢迎踏入我的博客世界&#xff0c;能与您在此邂逅&#xff0c;真是缘分使然&#xff01;&#x1f60a; &#x1f338;愿您在此停留的每一刻&#xff0c;都沐…

①常用API----Math

public static int abs(int a) // 返回参数的绝对值 public static double ceil(double a) // 返回大于或等于参数的最小整数 public static double floor(double a) // 返回小于或等于参数的最大整数 public static int round(f…

数据库调优厂商 OtterTune 宣布停止运营

昨天刷到消息&#xff0c;得知数据库优化厂商 OtterTune 停止了运营。OtterTune 的成员主要来自 CMU Andy Pavlo 教授领导的数据库实验室。公司正式成立于 2021 年 5 月&#xff0c;融资了 1450 万美金。 按照 Andy 教授的说法&#xff0c;公司是被一个收购 offer 搞砸了。同时…

pcr实验室和P2实验室装修设计中的区别

PCR实验室和P2实验室在装修设计的区别是什么&#xff1f;PCR实验室指的是基因扩增实验室&#xff0c;而P2实验室是指生物安全实验室中的一个分类&#xff0c;是生物安全防护达到二级的实验室。那么PCR实验室和P2实验室装修设计标准是什么&#xff1f;实验室装修公司小编为您详解…

【Python自动化测试】如何才能让用例自动运行完之后,生成一张直观可看易懂的测试报告呢?

小编使用的是unittest的一个扩展HTMLTestRunner 环境准备 使用之前&#xff0c;我们需要下载HTMLTestRunner.py文件 点击HTMLTestRunner后进入的是一个写满代码的网页&#xff0c;小编推荐操作&#xff1a;右键 --> 另存为&#xff0c;文件名称千万不要改 python3使用上述…

.net 奇葩问题调试经历之2——内存暴涨,来自非托管的内存泄露

📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:新的征程,我们面对的不仅仅是技术还有人心,人心不可测,海水不可量,唯有技术,才是深沉黑夜中的一座闪烁的灯塔序言 这是一个序列文章,请看以往文…

数据库同步最简单的方法

数据库同步到底有咩有简单的方法&#xff0c;有肯定是有的&#xff0c;就看你有咩有缘&#xff0c;看到这篇文章&#xff0c;你就是有缘人。众所周知&#xff0c;数据库同步向来都不是一件简单的事情&#xff0c;它很繁琐&#xff0c;很费精力&#xff0c;很考验经验&#xff0…

Hadoop版本演变、分布式集群搭建

Hadoop版本演变历史 Hadoop发行版非常的多&#xff0c;有华为发行版、Intel发行版、Cloudera Hadoop(CDH)、Hortonworks Hadoop(HDP)&#xff0c;这些发行版都是基于Apache Hadoop衍生出来的。 目前Hadoop经历了三个大的版本。 hadoop1.x&#xff1a;HDFSMapReduce hadoop2.x…