TypeScript五:类

成员属性与方法定义

class User {
    id: number;
    username: string;

    // 创建类的函数,当类通过new实例化的时候,就会执行该函数
    constructor(id: number,username: string) {
        console.log('这是构造函数,对类中成员属性进行初始化赋值');
        this.id = id;
        this.username = username;
    }

    postArticle(title: string) {
        // 在类的内部可以通过 `this` 来访问成员属性和方法
        console.log(`${this.username} 发表了一篇文章:${title}`)
    }
}

let user = new User(1,'my')
user.postArticle('test')//my 发表了一篇文章:test

public修饰符简化构造函数的赋值操作

class User {
    // id: number;
    // username: string;

    //不用再声明属性和赋值
    constructor(public id: number,public username: string) {
        // this.id = id;
        // this.username = username;
    }

    postArticle(title: string) {
        console.log(`${this.username} 发表了一篇文章:${title}`)
    }
}
let user = new User(1, 'my')
user.postArticle('test')//my 发表了一篇文章:test

继承extends

constructor

如果子类没有重写构造函数constructor,则会在默认的 constructor 中调用 super()

如果子类有自己的构造函数,则需要在子类构造函数中显示的调用父类构造函数 : super()

super

在子类构造函数中只有在 super() 之后才能访问 this

在子类中,可以通过 super 来访问父类的成员属性和方法

通过 super 访问父类的的同时,会自动绑定上下文对象为当前子类 this

class VIP extends User {
    constructor(id: number, username: string, public score = 0) {
        super(id, username);
    }
    postAttachment(file: string): void {
        //可以用super调用父类的方法,自动绑定上下文对象为当前子类 this
        super.postArticle(title);//Leo 发表了一篇文章:1.png
        console.log(`${this.username} 上传了一个附件: ${file}`)
    }
}
let vip1 = new VIP(1, 'Leo');
vip1.postArticle('标题');
vip1.postAttachment('1.png');

方法的重写与重载

子类成员方法继承自父类,但是子类也可以对它们进行重写和重载

重写

class VIP extends User {
    constructor(id: number, username: string, public score: number = 0) {
        super(id, username);
    }
   
    //重新实现了父类的方法:参数的个数和参数的类型一致 
    postArticle(title: string) {
        //重写方法内容
        this.score++;
        console.log(`${this.username} 发表了一篇文章: ${title},积分:${this.score}`);
    }
}

let vip1 = new VIP(1, 'Leo');
vip1.postArticle('标题');

重载

class VIP extends User {
    constructor(id: number, username: string, public score: number = 0) {
        super(id, username);
    }

    // 参数个数,参数类型不同:重载
    postArticle(title: string): void;
    postArticle(title: string, file: string): void;
    postArticle(title: string, file?: string) {
        if (file) {
            console.log(file)
        } else {
            super.postArticle(title);
        }
    }
}

let vip1 = new VIP(1, 'Leo');
vip1.postArticle('标题');
vip1.postArticle('标题', 'file');

修饰符

限制不同的访问级别

public修饰符

自身、子类、类外

protected饰符

自身。子类

private修饰符

自身

readonly 修饰符

只读修饰符只能针对成员属性使用,且必须在声明时或构造函数里被初始化

自身、子类、类外

寄存器

除了修饰符也可以用getter和setter来实现对属性的控制
class User {
    constructor(readonly _id: number, readonly _username: string, private _password: string) {
    }

    public set password(password: string) {
        if (password.length >= 6) {
            this._password = password;
        }
    }
    
    public get password() {
        return '******';
    }
}
let user1 = new User(1, 'mt', '123456');
console.log(user1.password);//******

静态成员

静态成员是属于类的,而不是实例后的对象。使用 类名.静态成员 来访问

type IAllowFileTypeList = 'png' | 'gif' | 'jpg' | 'jpeg' | 'webp';

class User {
  
    static readonly ALLOW_FILE_TYPE_LIST: Array<IAllowFileTypeList> = ['png', 'gif', 'jpg', 'jpeg', 'webp'];
    
    constructor(
        public id: number,
        public username: string,
        private _allowFileTypes: Array<IAllowFileTypeList>
    ) { }

    static info(): void {
        console.log(User.ALLOW_FILE_TYPE_LIST);//User类允许的文件类型

    }
    
    info2(): void {
        console.log(this._allowFileTypes);//实例后的对象允许的文件类型
    }
}

let user1 = new User(1, 'mt', ['png', 'gif']);
console.log(User.ALLOW_FILE_TYPE_LIST);//[ 'png', 'gif', 'jpg', 'jpeg', 'webp' ]
User.info();//[ 'png', 'gif', 'jpg', 'jpeg', 'webp' ]
user1.info2();//[ 'png', 'gif' ]

抽象类abstract

有时候,一个基类(父类)的一些方法无法确定具体的行为,而是由继承的子类去实现

使用抽象类可以约定所有继承子类的所必须实现的方法,使类的设计更加的规范。

注意事项

abstract 修饰的方法不能有方法体

如果一个类有抽象方法,那么该类也必须为抽象的

如果一个类是抽象的,那么就不能使用 new 进行实例化(因为抽象类表名该类有未实现的方法,所以不允许实例化)

如果一个子类继承了一个抽象类,那么该子类就必须实现抽象类中的所有抽象方法,否则该类还得声明为抽象的

例子:React组件设计

abstract class Component<T1, T2> {

    props: T1;
    state: T2;

    constructor(props: T1) {
        this.props = props;
    }

    abstract render(): string;
}

类与接口 implements

当一个抽象类中只有抽象的时候,这个时候,更推荐通过接口的方式来定义契约。

抽象类编译后还是会产生实体代码,而接口不会

TypeScript 只支持单继,但是一个类可以实现多个接口,多个接口使用 , 分隔

implements 与 extends 可同时存在

interface ILog {
    getInfo(): string;
}

interface IMyComponentProps {
    val: number;
}

interface IMyComponentState {
    x: number;
}

class MyComponent extends Component<IMyComponentProps, IMyComponentState> implements ILog {

    constructor(props: IMyComponentProps) {
        super(props);
        this.state = {
            x: 1
        }
    }

    render() {
        return '123';
    }

    getInfo() {
        return `组件:MyComponent,props:${this.props},state:${this.state}`;
    }

}

多个接口用,号分割

interface ILog {
    getInfo(): string;
}
interface IStorage {
    save(data: string): void;
}
class MyComponent extends Component<IMyComponentProps, IMyComponentState> implements ILog, IStorage {
    //...
}

接口也可以继承

interface ILog {
    getInfo(): string;
}
interface IStorage extends ILog {
    save(data: string): void;
}

类与对象类型

当我们在 TypeScript 定义一个类的时候,其实同时定义了两个不同的类型

类类型(构造函数类型,js的类本质是个函数)

对象类型(实例后的对象)

class Person {
    // 属于类的
  static type = '人';

  // 属于实例的
  name: string;
  age: number;
  gender: string;

  // 类的构造函数也是属于类的
  constructor( name: string, age: number, gender: '男'|'女' = '男' ) {
    this.name = name;
    this.age = age;
    this.gender = gender;
  }
    
  // 属于实例的
  public eat(): void {
    // ...
  }
}

对应于以下两种接口

interface Person {
    name: string,
    age: number,
    gender: string,
    eat(): void
}
    
interface PersonConstructor {
    //构造函数的标注前面要加个new
    new (name: string, age: number, gender: '男'|'女'): Person,
    type: string
}

使用时的类型标注区别如下

// 接受实例类型
function fn1(arg: Person) {
  arg.eat();
}

fn1(new Person('zMouse', 35, '男'));

// 接受类/构造函数
function fn1(arg: typeof Person) {
  new arg('zMouse', 35, '男');
}

fn1(Person);
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容