前言
前一篇文章说了TS的基本的数据类型和一些语法结构 这一章就将剩下的类 接口什么的说完吧(都是个人浅显的理解 有不对的地方评论区指正一下 麻烦了)
TS中的类
TS中的其实就和ES6中的类一模一样
定义一个简单的类
// 使用class关键字定义一个类
class Person{
// 定义属性
name: string = '张三',
// 定义方法
sayHello() {
console.log('你好')
}
}
// 调用
const per = new Person()
console.log(per.name)
per.sayHello()
实例、静态、只读
class Person{
// 定义一个实例属性
name: string = '张三'
// 定义一个类属性(静态属性)
static age: number = 18
// 定义一个只读属性
readonly sex: string = '男'
// 同理在方法前面加上static关键字 就说明当前方法是类方法
static sayHello() {
console.log('你好')
}
}
// 调用
const per = new Person()
// 调用实例属性
console.log(per.name) //输出张三
// 调用静态属性
console.log(Person.age)
// 调用静态方法
Person.sayHello()
构造函数
class Person{
name: string;
age: number;
constructor(name: string, age: number) {
// 在实例方法中 this就表示当前的实例
// 在构造函数啊中当前对象就是当前新创建的对象
// 可以通过this向新建的对象中添加属性
this.name = name;
this.age = age
}
}
const per = new Person('张三',18)
console(per)
继承
class Father{
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello() {
console.log('你好')
}
}
// 通过extends关键字继承
// 此时Father被称为父类 Son被称为子类
// 使用继承后 子类将会拥有父类的所有属性和方法
// 通过继承可以将多个类中拥有的代码写在一个父类中
// 这样可以只需写一次就可以让所有子类同时拥有父类的所有属性和方法
// 如果希望在子类中添加父类没有的属性和方法 直接加就行
// 如果在子类中添加了与父类相同的方法 则子类的方法就会覆盖掉父类的方法(子类覆盖掉父类的方法称为:方法重写)
class Son extends Father{
run() {
console.log(`${this.name}在跑~`)
}
sayHello() {
console.log('儿子,你好')
}
}
const son = new Son('儿子',18)
console.log(son)
son.run() // 输出 儿子在跑
son.sayHello()// 输出 儿子,你好
super关键字
class A{
name: string;
constructor(name: string) {
this.name = name;
}
say() {
console.log('AAA')
}
}
class B extends A{
age: number;
constructor(name: string, age: number) {
// 如果在子类中写了构造函数 在子类构造函数中就必须对父类的构造函数进行调用
super(name) // 调用父类的构造函数
this.age = age
}
say() {
// 在类方法中 super就表示当前类的父类
super.say()
}
}
抽象类
// abstract 开头是抽象类
// 抽象类和其他类的区别不大 只是不能用来创建对象
// 抽象类就是用来专门继承的
// 抽象类可以添加抽象方法
abstract class A{
name: string;
constructor(name: string) {
this.name = name;
}
abstract say(): void;
}
class B extends A{
say() {
console.log('bbb');
}
}
const b = new B('b');
b.say()
接口
// 接口就是用来定义一个类结构
// 用来定义一个类中应该包含哪些属性和方法
// 同时也可以当成类型声明去使用
// 定义一个接口
interface myInterface{
name: string;
age: number
}
const obj: myInterface = {
name: '孙悟空',
age: 18
}
// 接口可以定义类的时候来限制类的结构
// 接口中的所有属性都不具有实际值
// 接口只定义对象的结构 而不考虑实际的值
// 在接口中 所有的方法都是抽象方法
interface myInter{
name: string;
say(): void;
}
// 定义类时 可以使用类来实现一个接口
// 实现接口就是满足接口的要求
// 通过 implements 关键字来进行实现
class My implements myInter{
name: string;
constructor(name: string) {
this.name = name;
};
say() {
console.log('111');
}
}
属性的封装
// TS可以在属性前添加属性的修饰符
// public 修饰的属性表示可以在任何位置访问(修改)任何值
// private 私有属性 私有属性只能在类的内部进行访问(修改)
// -通过在类中添加方法使得私有属性可以被外部访问
// protected 受保护的属性 只能在当前类和子类中访问(修改)
class Person{
protected names: string;
private age: number;
constructor(name: string, age: number) {
this.names = name;
this.age = age;
}
// TS中设置getter方法
get name() {
return this.names
}
set name(value:string) {
this.names = value
}
}
const per = new Persson('小王',33)
per.name = '小张'
console.log(per.name)
// 现在属性都是对象中设置的 属性可以被随意的修改
per.name = '小朱';
per.age = 50;
per.setName('小张');
console.log(per.getName());
泛型
// 在定义函数或者是类的时候 如果遇到类型不明确的就可以使用泛型
function fn<T>(a: T):T {
return a
}
// 可以直接调用具有泛型的函数
fn(1) // 不指定泛型 TS可以直接对类型进行推断
fn<string>('hello') // 指定泛型
function fn2<T, K>(a: T, b: K):T {
return a
}
fn2('zbc',123)
interface Inter{
length: number
}
// T extends Inter 表示泛型T必须是Inter的实现类(子类)
function fn3<T extends Inter>(a: T) {
return a.length
}
fn3('123')