TypeScript 面向对象

定义类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class C {
constructor(n: string) {
this.name = n;// 构造函数,为定义的属性赋值
}
name: string; // 定义属性 省略前面的public关键字

readonly age:number = 18 // 只读属性

static readonly age: number = 1;

run():void{ // 定义方法
console.log('void')
}

}

接口

定义类的结构,声明包含的属性和方法,接口也可以当作类型声明去使用

接口可以在定义类的时候限制类的结构,接口中所有属性都不应该有实际的值

接口只定义对象的结构,接口中的所有方法都是抽象方法

同名结构声明的类型会合并,如果一个对象使用了该接口,必须包含所有的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
interface MyObj {
prop1: string,
prop2: number
}
interface MyObj {
prop3: Boolean
}

const obj: MyObj = {
prop1: '1',
prop2: 2,
prop3: true,
}

接口可以描述类的行为
定义类时可以让类去实现一个接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface PersonInterface {
// 只读属性
readyonly name: string,
age: number,
say(method: string): boolean
}

class JiaZhen implements PersonInterface {
name: string = '1';
age: number = 1;
say(method: string): boolean {
return true;
}
}

使用接口描述一个类的实例化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
interface PersonInterface{
name:string,
new(name:string):Person
}

class Person{
constructor(name:string) {
}
}

function createPerson(Clsss:PersonInterface,name:string) {
return new Clsss(name);
}

createPerson(Person,'aaa');

属性的封装

类的属性如果可以随意被修改,可能导致运算时的错误

TS提供了三种属性的修饰符

public: 公有 在类,子类 类外面都可以访问

1
2
3
4
5
6
class Person {
constructor(pubilc name:string){
// 表示添加到实例上。可以通过属性访问
}
}
new Person().name

protected: 保护类型 在类里面,子类里面可以访问,在类外部没法访问

private: 私有 在类里面可以方法,子类,类外都不能访问

属性如果不加修饰符就是共有

泛型

定义函数或者类时遇到类型不确定时使用泛型,可以使用多个

1
2
3
4
5
6
7
function jiazhen<Z>(age: Z): Z {
return age;
}

jiazhen(19);

jiazhen<Number>(19) // 主动指明泛型

指明泛型Z必须是interface的实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
interface Zhen {
age: number,
love(who: string): boolean
}

function jiazhen<Z extends Zhen>(obj: Z): any {
return obj.love;
}

jiazhen<Zhen>({
age: 1,
love(a) {
return true;
}
})

指明类初始化时的泛型

1
2
3
4
5
6
7
8
class A<T>{
name: T;
constructor(a: T) {
this.name = a
}
}

new A<string>('10')

类装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function enhancer(target:any){
target.prototype.name = '11';
}

interface Person{
name:string
}

@enhancer
class Person {
constructor(){

}
}

const p = new Person();
p.name;

属性装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

// 如果装饰的是普通的属性,target指向类的原型
// 如果是static属性,target指向类的定义
function upperCase(target:any,propname:string) {
let v = target[propname];
const getter = ()=>v;
const setter = (newValue:string)=>{
v = newValue.toUpperCase();
}
delete target[propname];
Object.defineProperty(target,propname,{
set:setter,
get:getter,
enumerable:true,
configurable:true
})
}

interface Person{
name:string
}

class Person {
@upperCase
name = 'girl'
constructor(){

}
}

const p = new Person();
console.log(p.name);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function unEnumber(enumConfig:boolean) {
// 属性描述器
return function unEnumber(target:any,propname:string,propertyDescriptor:PropertyDescriptor) {
propertyDescriptor.enumerable = enumConfig;
}
}

interface Person{
name:string
}

class Person {
name = 'girl'
constructor(){}

// getname 不能枚举
@unEnumber(false)
getName(){}
}

const p = new Person();
console.log(p.name);

for(let key in p){
console.log(key)
}

可以对方法的逻辑进行包装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function trans(target:any,propname:string,propertyDescriptor:PropertyDescriptor) {
const oldValue = propertyDescriptor.value;
console.log("1------------")
propertyDescriptor.value = function getNumber(...args:any[]) {
args = args.map(item=>Number(item));
console.log("2------------")
return oldValue.apply(this,args);
}
}

interface Person{
name:string
}

class Person {
name = 'girl'
constructor(){}

@trans
getNumber(...args:any[]){
console.log("3------------")
return args.reduce((sum,item)=>{ sum+=item; return sum },0);
}

}

const p = new Person();

console.log(p.getNumber('1',2,'3'));

参数修饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//              类的原型    方法名             被修饰参数的索引
function dubble(target:any,methodName:string,index:number) {
target.num = 'num'
}

class Person {
getNumber(@dubble num:number){
console.log(num);
console.log(this.num);
}
}

const p = new Person();

p.getNumber(2);

抽象类

不能当作构造函数,抽象方法必须被子类实现

1
2
3
4
5
6
7
abstract class Person {
abstract say(): void
}

class Lisa extends Person {
say() { }
}

重写和重载

重写:子类中重写继承自父类的方法

1
2
3
4
5
6
7
class Person {
say(){}
}

class Boy extends Person{
say(){}
}

重载:为一个函数提供多个类型的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
// 函数重载表示同名的函数如果参数不同函数会重载

// 但是JS中没有重载的概念,下面同名的函数会覆盖上面的函数

// TS中模拟函数重载, 通过不同的参数类型校验

function fn(a: number): number;
function fn(b: string): string;
function fn(c: any): any {
if (typeof c === 'number') {
return c + 1;
}
};
打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2015-2025 SunZhiqi

此时无声胜有声!

支付宝
微信