TypeScript学习笔记——第四节

本文深入探讨了TypeScript的面向对象特性,包括类、继承与多态。介绍了类的定义、构造函数、属性的封装、抽象类和接口的使用。通过实例展示了如何实现继承,以及多态的概念。此外,还讲解了泛型在函数和类中的应用,以提高代码的复用性和灵活性。
摘要由CSDN通过智能技术生成

面向对象简介

面向对象是程序设计语言中一个非常重要的思想,初次接触是在学习java时,当时对于面向对象的学习没有很精通,索性借着学习ts的机会认真的研究一下。
所谓面向对象,首先将对象当做一个名词去理解,面向着他开发,程序之中的所有操作都需要通过对象去完成,举个例子,在前端开发中的:

  • 操作浏览器需要借助window对象
  • 操作网页需要使用document对象
  • 操作控制台需要借助console对象

那么对象是什么呢?可以说:世间万物都是对象。像是一个人,一只猫咪,一颗子弹等等,都可以抽象成程序中的对象。程序中所有的对象都被分为两个部分数据和功能,以一个人为例,他的身高、体重、姓名、年龄等属于数据,人可以说话、走路、吃饭,这些属于人的功能。数据在对象中被称为属性,功能则被称为方法

类(class)

了解了对象之后,我们还要知道在程序中如何创建对象。要想创建对象,必须要先定义类,所谓类(class),可以理解为对象的模型,程序中可以使用类传递不同的参数创建特定的对象
语法:

class 类名{
	属性名: 类型
	...
	constructor(参数1: 类型, 参数2: 类型...){
		this.属性名 = 参数
		...
	}
	方法名(){
		/*...*/
	}
}

举例:定义一个Person类

class Person{
	name: string;
	age: number;
	constructor(name: string, age: number){
		this.name = name
		this.age = age
	}
	walk(){
		console.log(this.name + '在走路')
	}
}
const person = new Person('wmh', 18) //实例一个Person对象

注:可以直接将属性定义在构造函数中

关于属性:

  • 直接定义的属性是实例属性,必须通过对象的实例访问
person.name = 'wyz'
  • 使用static关键字修饰,表明声明一个静态属性(类属性),类属性需要直接使用类来调用
console.log(Person.静态属性名)
  • 使用readonly关键字修饰,表明声明一个只读属性,只能进行读操作
  • 使用public关键字修饰,默认值,表示可以在任意地方访问
  • 使用private关键字修饰,私有属性,只能在类内部进行访问
  • 使用protected关键字修饰,只能在当前类和当前类的子类中访问

继承与多态

1. 继承
  • 对于继承这个概念,用例子来说明,假设在一个程序中需要用到Dog和Cat两个类,从构成来看,这两个类有许多部分可以共用,单独定义的话就会造成代码的冗余,此时我们就可以将这两个类的公共部分提取出来,定义一个Animal类,让Dog和Cat类继承Animal类所有的属性和方法,特定的属性方法单独定义,这就是继承。
// Animal类
class Animal{
    name: string;
    age: number;
    constructor(name: string, age: number){
        this.name = name;
        this.age = age;
    }
    bark(){
	 	console.log('动物在叫~~')
	}
}
// Dog类
class Dog extends Animal{
    bark(){
        console.log(`${this.name}在汪汪叫!`);
    }
}
// Cat类
class Cat extends Animal{}

const dog = new Dog('旺财', 4);
const cat = new Cat('小金', 5)
dog.bark();
  • 此时Dog和Cat类也成为子类、派生类,Animal类被称为父类、超类
  • 如果在子类中添加了和父类同名的方法,则子类会覆盖掉父类的方法,这种形式,我们称为方法重写
  • 在子类的方法中,super就表示当前子类的父类,如果在子类中写了构造函数,则需要在子类的构造函数中调用super(参数),表明调用父类的构造函数
2. 多态

参考知乎: https://www.zhihu.com/question/30082151.
花木兰替父从军(摘自知乎)

抽象类与接口

1. 抽象类
  • abstract修饰的类被称为抽象类,与一般的类相比,抽象类不能用来创建实例对象,只能被其他的类继承,抽象类中可以定义抽象方法
  • 抽象方法同样以abstract修饰,不含方法体,只能定义在抽象类中,抽象类的子类必须重写抽象方法
abstract class Person{
	abstract sayHello(): void; //抽象方法
}
2. 接口
  • 通俗的来说,接口就是用来定义一个类的结构,限制一个类中需要包含的属性和方法
  • 在定义类的时候使用implements关键字实现接口
  • 实例
interface Person{
    name: string;
    sayHello():void;
}

class Student implements Person{
    constructor(public name: string) {
    }

    sayHello() {
        console.log('大家好,我是'+this.name);
    }
}
3. 抽象类与接口的对比
  • 抽象类中的方法可以是抽象方法,也可以不是;接口中的属性方法都只能是抽象的,不能有实际值,它只是用来限制结构
  • 在同一作用域中,抽象类不可以重名,但接口可以,他会合并重名接口中的属性方法
  • 一个类只能继承至一个抽象类,但可以实现多个接口

属性的封装

  • 由于常规的定义方式会使得类的属性暴露在外,不建议这么做,一般会采用对类的属性进行访问的限制,private或protected修饰,再配合类内部的getter和setter方法对属性进行访问
  • 实例:
class Person{
    private _name: string;

    constructor(name: string){
        this._name = name;
    }

    get name(){
        return this._name;
    }

    set name(name: string){
        this._name = name;
    }

}

const p1 = new Person('孙悟空');
console.log(p1.name); // 通过getter读取name属性
p1.name = '猪八戒'; // 通过setter修改name属性

泛型

  • 定义一个函数或是一个类时,有时候会出现无法确定类型的情况,包括参数、属性、返回值的类型,此时泛型便可以发挥作用
  • 举个例子:
function test(arg: any): any{
	return arg;
}

上例中,test函数的参数类型无法确定,但可以确定参数和返回值类型相同,由于类型不确定所以使用any类型,但这样明显是不合适的,首先any会关闭ts的类型检查,其次这样也无法体现参数和返回值是相同类型

  • 这里我们就可以使用泛型
function test<T>(arg: T): T{
	return arg;
}

这里的<T>就是一个泛型,T是这个泛型的名字(自定义),定义之后即可在函数或类中使用这个泛型,泛型其实就表示某个类型

对于上述的函数,有两种使用方式

  • 方式一(直接使用):视作普通函数
test(10)
  • 方式二(指定类型):在函数后制定泛型的类型
test<string>('wmh')

另外,可以同时指定多个泛型,泛型间使用逗号隔开

function test<T, K>(a: T, b: K): K{
	const x = a
    return b;
}

test<number, string>(10, "hello");

在类中也可以使用泛型:

class MyClass<T>{
    prop: T;

    constructor(prop: T){
        this.prop = prop;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值