TS中的类(class)

本文介绍了面向对象编程的基本概念,包括类与对象、封装、继承和多态。通过实例展示了如何在 TypeScript 中实现这些概念,如创建动物类、狗类和猫类,并探讨了权限修饰符(public、private、protected)以及静态属性和方法。此外,还提到了接口定义,以及泛型在类型系统中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

类(class): 定义了一切事物的抽象特点(属性和方法)
对象(object): 类的实例(通过 new 来生成)
面向对象特点: 封装,继承,多态

  • 封装: 将操作数据的细节隐藏起来,只暴露接口, 调用者只需要通过接口来访问对象
  • 继承: 子类继承父类, 子类除了拥有父类的特性外还可以拥有更加具体的特性
  • 多态: 同一个方法可以有不同的响应(猫和狗都继承自动物类,但是他们叫声各有不同)

封装

抽象一个动物类, 拥有名字属性和奔跑的动作,创建一个基本类 基类(动物类)

// 创建基本类 基类
class Animal {
	// 属性
	name: string 
	// 构造函数
	constructor(name: string) {
		this.name = name
	}
	// 方法 奔跑
	run(){
		return `${this.name} runing`
	}
}
// 实例化类
const snake = new Animal('lily')
console.log(snake.name)
console.log(snake.run())

继承

创建一个狗类继承自动物类

// 延用上面的 Animal 类
class Dog extends Animal {
	// 实现了一个方法 -- 叫
	bark() {
		return `${this.name} is barking`
	}
}
const xiaobao = new Dog('小宝')
xiaobao.name
xiaobao.run()
xiaobao.bark()

多态(方法重写)

方法重写是多态一种表现形式,类似的还有方法的重载 和 接口的定义

// 延用上面的 Animal 类
class Cat extends Animal {
	// 重写构造函数,在子类的构造函数中必须调用 super() 方法
	constructor (name) {
		super(name)
		console.log(this.name)
	}
	// 重写run方法 通过 super 关键字调用父类方法或属性
	run () {
		return `Meow, ${super.run()}`
	}
}
// 实例化 Cat 方法
const maomao = new Cat('毛毛')
console.log(maomao.run())

修饰符

作用: 对类的属性和方法提供权限控制

  • public: 公有的可以在任何地方可以被访问和修改(类中属性和方法默认为publish)
  • private: 私有的仅在当前类可访问和修改
  • protected: 仅当前类与子类(继承类)可以访问和修改
  • readonly: 只读修饰符, 仅可访问不可修改

public 修饰符的使用

// 延用上面的 Animal 类
class Animal {
	// public 修饰符,也可以不加, 属性与方法默认就是 public
	public name: string 
	// 构造函数
	constructor(name: string) {
		this.name = name
	}
	// 方法 奔跑
	run(){
		return `${this.name} runing`
	}
}
// 实例化类
const snake = new Animal('lily')
console.log(snake.name) // => lily
// 把 name 属性修改为 lucy
snake.name = 'lucy'
console.log(snake.name) // => lucy

private 修饰符的使用

class Animal {
	/* 私有的仅在当前类可访问和修改 */
	private name: string  
	// 构造函数
	constructor(name: string) {
		this.name = name
	}
	// 方法 奔跑
	run(){
		return `${this.name} runing`
	}
}
// 实例化类
const snake = new Animal('lily')
console.log(snake.name) // 报错 私有的只能在 Animal 类中访问和更改
// 把 name 属性修改为 lucy
snake.name = 'lucy' // 报错 私有的....
console.log(snake.name) // => 报错 私有的....

protected 修饰符的使用

class Animal {
	/* protected 仅当前类与子类(继承类)可以访问和修改 */
	protected name: string 
	// 构造函数
	constructor(name: string) {
		this.name = name
	}
	// 方法 奔跑
	run(){
		return `${this.name} runing`
	}
}
// Dog 类继承自 Animal
class Dog extends Animal {
	// 实现了一个方法 -- 叫
	bark() {
		// `子类`可以访问父类的属性 name
		return `${this.name} is barking`
	}
}
const xiaobao = new Dog('小宝')
xiaobao.name
xiaobao.run()
xiaobao.bark()

readonly 的使用与public private protected 用法一样, 被readonly 修饰过的属性,只能读取,不能修改,这里就不演示了

静态属性和静态方法

静态: 不需要实例化类, 可以在类上直接访问或调用的属性和方法
静态属性访问方式 不需要实例化, 通过 类名点属性名或方法名 方式访问
静态属性访问:类名.属性名
静态方法调用:类名.方法名

// 创建基本类 基类
class Animal {
	// 定义只读属性 name
	readonly name: string
	// 定义静态属性
	static categoies: string[] = ['mammal','bird']
	// 定义静态方法
	static isAnimal(a) {
		return a instanceof Animal // 判断 a 是否为 Animal 的实例
	}
	// 构造函数
	constructor(name: string) {
		this.name = name
	}
	// 方法 奔跑
	run(){
		return `${this.name} runing`
	}
}
// 注意! 访问 静态属性和方法不需要实例化

// 访问静态属性 categoies
console.log(Animal.categoies)

// 访问 name 属性
const snake = new Animal('lily')
console.log(snake.name)// 注意 name 是 snake 实例的属性

// 调用静态方法
console.log(Animal.isAnimal(snake)) // 判断 snake 是否为 Animal 的实例

区分两个概念

  • 类实例上的属性和方法
    我们在讨论静态属性和方法之前访问属性和方法,都是必须实例化然后访问
    const snake = new Animal('lily') // 实例化
    console.log(snake.name) // 访问实例的属性
    snake.run() // 调用实例的方法
  • 静态属性和方法
    console.log(Animal.categoies) // 不需要实例化 使用类名直接访问
    Animal.isAnimal(snake) // 不需要实例化, 使用类名直接调用
  • 结论:静态属性和方法的定义与实例的状态没有太大的关系

接口定义

接口定义是对不同类中共性的抽象,实际上也是多态的一种表现形式, 在面向对象中一个类只能继承自另外的类, 有时候不同类之间,会有一些共有的特性,用子类继承父类的方法,很难完成对不同类中共性的抽象
举个列子 有 汽车类 和 手机两个没有任何关联的类, 汽车和手机都有收音机, 对于收音机的开关功能就可以定义一个接口让手机类和汽车类继承过去

  • interface 接口定义
  • implements 接口实现
// 汽车类
class Car {
	switchRadio() {} // 收音机开关功能
}
// 手机类
class Phone {
	switchRadio() {} // 收音机开关功能
}

上面的 Car 类和 Phone 类都有相同的特性,都有 switchRadio 功能, 可以把 switchRadio 提取出来, 如果用父类的方式, 必须为 Car 类和 Phone 找一个共同的父类,感觉很难做到,这时候 可以把共有的特性, 提取成一个 interface 通过 implements 关键字让两个类都去实现它

// 提取 Radio 接口
interface Radio {
	// 定义 switchRadio 方法, 接受boolean类型的形参, 返回值 void
	switchRadio(trigger: boolean): void
}

// 汽车类
class Car implements Radio {
	switchRadio() {} // 收音机开关功能
}
// 手机类
class Phone implements Radio {
	switchRadio() {} // 收音机开关功能
}

现在新增一个功能,检查电量, 这个功能仅手机有,汽车没有, 再定义一个接口 Battery

// 提取 Radio 接口
interface Radio {
	// 定义 switchRadio 方法, 接受boolean类型的形参, 返回值 void
	switchRadio(trigger: boolean): void
}

// 汽车类
class Car implements Radio {
	switchRadio() {} // 收音机开关功能
}

// 实现方式一
interface Battery { 
	checkBattery(); // 检查剩余电量
}
class Phone implements Radio,Battery  { // 实现多个接口的定义时, 用逗号隔开
	switchRadio() {} // 收音机开关功能
	checkBattery() {} // 检查剩余电量
}


// 实现方式二
interface RadioWithBattery extends Radio {
	// 继承 Radio 接口就可以拥有 Radio 的属性方法, 同时还可以定义差异化的属性和方法
	checkBattery(); 
}
// phone 类实现 IBattery 接口定义
class Phone implements RadioWithBattery {
	switchRadio() {} // 收音机开关功能
	checkBattery() {} // 检查剩余电量
}

TS中的泛型

### TypeScript (TS) 中的 `class` 概念 TypeScript 是 JavaScript 的超集,它扩展了 JavaScript 来提供更好的型安全性和结构化支持。在 TypeScript 和 ES6 中引入的 `class` 关键字用于创建(即面向对象程序设计的基础),这允许更清晰地组织代码并提供更强大的特性。 #### **什么是 (`class`)** 定义了一种型的实例(对象)的行为和属性。通过使用 `class` 关键字,您可以声明一个新的,该可以包含构造函数、静态方法、成员变量和方法。 #### **构造函数** 构造函数是的特殊方法,当创建的新实例时自动调用。它们通常用于初始化实例的状态: ```typescript class MyClass { constructor(private myAttribute: any) { // 初始化操作 } } ``` 在这个例子中,`MyClass` 有一个私有属性 `myAttribute`,其在构造函数中设置。 #### **继承** 也可以从其他派生(继承),这使得子可以重用父的功能,并且能够定义自己的行为: ```typescript class ParentClass { public method() { // 方法实现 } } class ChildClass extends ParentClass { override method() { // 覆盖父的方法实现 } } ``` 这里,`ChildClass` 继承自 `ParentClass` 并重写了其方法。 #### **接口和型约束** 在 TypeScript 中,还可以使用接口来描述对象的形状(包括属性和方法)。结合 `extends` 关键字,可以通过实现接口来明确指定它的行为和结构: ```typescript interface MyInterface { name: string; greet(): void; } class MyClass implements MyInterface { constructor(public name: string) {} greet() { console.log(`Hello, ${this.name}!`); } } ``` 在这个例子中,`MyClass` 实现了一个名为 `MyInterface` 的接口。 ### **使用 `type` 进行约束** 在您的引用示例中展示了如何使用 `type` 进行泛型型约束。这允许创建更具灵活性的函数,可以根据传递给它们的具体型执行不同的逻辑: ```typescript type Class = string; function result<T extends Class>(val: T): T { console.log(val.length); return val; } result<string>("zhangsan"); ``` 这个 `result` 函数接受一个参数,假设它是某种型(这里通过 `T extends Class` 进行约束),并返回相同的值。型断言 (`<string>`) 表明调用者知道传递的是字符串型。 --- ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gleason.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值