TS的静态属性,静态方法,多态,抽象类

1,718 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情

前言

本篇围绕TS的的静态属性,静态方法,抽象类进行一个总结和介绍区分其使用方式,在这里分享给大家,一起学习,相互进步!如果有写的不对的地方,欢迎掘友们指出,弥补自己的不足,这会促使我不断在前端的道路上努力进步!

一.TS的静态属性和方法

静态属性和静态方法是不需要通过new实例就可以调用的属性和方法,在TS中我们用关键字static来定义其静态属性和方法,通过类直接使用。

class Student{
  static time:string='00:00'
  static goSchool(){
    console.log('上学啦')
  }
}
console.log(Student.time)
Student.goSchool()

接下来看下图:可以看出实例化的对象无法调用静态方法和静态属性

如果在实例化对象中的公共方法非要使用静态属性,改为Student.time

image.png

下图可以看出:静态方法无法使用非静态的属性【除去name默认为该类名】

image.png

二.多态

多态的出现是为了写出更加通用性的代码。

包括两种情况:

  • 重载(overload):一个函数,根据传入的实参值不同,选择执行不同的逻辑
  • 重写(override):子类重写继承自父类的方法(子对象中定义了和父对象中同名的方法,该方法指向子类)

1.重写: 前提是继承关系

class Person {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  eating() {
    console.log("Person eating");
  }
}

class Student extends Person {
  sno: number;

  constructor(name: string, age: number, sno: number) {
    // super调用父类的构造器
    super(name, age);
    this.sno = sno;
  }

  //子类方法重写(如果子类有方法有些调用子类的,没有则继承父类的方法)
  eating() {
    console.log("student eating");
    super.eating();
  }

  studying() {
    console.log("studying");
  }
}

2.重载:


type numberType = 0 | 1 | 2;

function test(a?: numberType):number;

function test(a = 1):number | void {
    console.log(a)
}

test(); // 1

test(2) // 2

三.抽象类&抽象方法

  • 抽象类:不能被实列化,抽象方法必须被子类实现。抽象类使用关键字abstract来定义。
  • 抽象方法:父类并不需要对某些方法进行具体实现,所以在父类定义的方法叫抽象方法。

1.抽象类:


abstract class Animal {
  abstract eat():any ;
}

let a=new Animal();  // error:无法创建抽象类的实例

2.抽象方法:


// 父类
abstract class Animal {
  public name: string;
  constructor(name: string) {
    this.name = name;
  }

  abstract eat(): any;
}
// 子类Dog
class Dog extends Animal {
  constructor(name: string) {
    super(name);
  }
  // 抽象类的子类必须实现抽象类里面的抽象方法
  eat() {
    console.log(this.name + '吃饭了');
  }
}

四.public,private,protected的区别

  • public: 可以在任意位置访问(修改)默认值
  • private: 私有属性,只能在类的内部进行访问(修改)
  • protected:允许在类内及继承的子类中使用

三者主要的区别其实就是控制了类内部的属性和方法可被调用的范围

class Person {
    protected name!:string; //强制解析(也就是告诉typescript编译器,我这里一定有值)
    private age!:number;
    public say(){
        this.name
        this.age
        console.log('age:'+this.age,'name:'+this.name)
    }
    private eat(){
        this.say()
    }
    
}

class Student extends Person{
    public run(){
        this.name  //子类继承父类中peotected的name

    }
    public set(){
        this.eat() //error: eat方法是private的,只能在类内部访问,所以无法调用
    }

}

const person=new Person()
person.name='kkkk'  //error: name为protected 只能在类内和继承的子类下使用
person.age=19
console.log(person.name,person.age)
person.say() //public  类内外都可以使用
person.eat() //error: private  类外不能使用

const student=new Student()
student.set() // set 访问类型为 public 所以可在外部调用

image.png

聊一聊 private 和 # 的区别

typescript 在 3.8版本增加 ECMAScript Private Fields # 。#是对于es规范的private 成员变量实现。

其实上方代码使用private(或者protected)修饰的成员变量虽然提示了报错,但实际情况,你打印该变量实际还是执行的person.name打印为'kkkk',private eat()也会执行该方法。
private仅仅是一个检查和进行一个警告,#使用了weakmap实现了真正的私有。

举例:

class Person {
  #name: string;
  private age:number
  constructor(name: string,age:number) {
    this.#name = name;
    this.age=age;
  }
  greet() {
    console.log(`my name is ${this.#name}!age is ${this.age}`);
  }
}
let nike = new Person("nike ",18);
nike.#name='hh'; //编译时直接提示错误,并且打印直接为报错
nike.age=20      
nike.greet()

大家可以自己把该代码转化成JS代码看其实现原理,这边就不做多详细讲解了。