美文网首页
TypeScript类的使用(六)

TypeScript类的使用(六)

作者: 未路过 | 来源:发表于2022-09-21 00:09 被阅读0次

    1.类的定义

    1. 使用class关键字来定义一个类;
    2. 我们可以声明一些类的属性:在类的内部声明类的属性以及对应的类型
    • 如果类型没有声明,那么它们默认是any的;
    • 我们也可以给属性设置初始化值;
    • 在默认的strictPropertyInitialization模式下面我们的属性是必须初始
      化的,如果没有初始化,那么编译时就会报错;
    • 如果我们在strictPropertyInitialization模式下确实不希望给属性初
      始化,可以使用 name!: string语法;
    1. 类可以有自己的构造函数constructor,当我们通过new关键字创建一个实例时,构造函数会被调用;
    • 构造函数不需要返回任何值,默认返回当前创建出来的实例;
    1. 类中可以有自己的函数,定义的函数称之为方法;
      js
          class Person {
            name = "why";
            age = 18;
            eating() {
              console.log("eating");
            }
          }
    

    这里面的name和age都是在Person这个函数自身的,eating是在Person的prototype上的。
    Class 的基本语法 - ECMAScript 6入门 (ruanyifeng.com)
    ES2022 为类的实例属性,又规定了一种新写法。实例属性现在除了可以定义在constructor()方法里面的this上面,也可以定义在类内部的最顶层。

    // 原来的写法
    class IncreasingCounter {
      constructor() {
        this._count = 0;
      }
      get value() {
        console.log('Getting the current value!');
        return this._count;
      }
      increment() {
        this._count++;
      }
    }
    

    上面示例中,实例属性_count定义在constructor()方法里面的this上面。

    现在的新写法是,这个属性也可以定义在类的最顶层,其他都不变。

    class IncreasingCounter {
      _count = 0;
      get value() {
        console.log('Getting the current value!');
        return this._count;
      }
      increment() {
        this._count++;
      }
    }
    

    ts中类的写法

    class Person {
    //定义属性的时候必须初始化值
      name: string = ""
      age: number = 0
    
      eating() {
        console.log(this.name + " eating")
      }
    }
    
    const p = new Person("why", 18)
    console.log(p.name)
    console.log(p.age)
    p.eating()
    
    export {}
    
    

    或者
    在constructor里面做初始化

    class Person {
      name: string
      age: number
    
      constructor(name: string, age: number) {
        this.name = name
        this.age = age
      }
    
      eating() {
        console.log(this.name + " eating")
      }
    }
    
    const p = new Person("why", 18)
    console.log(p.name)
    console.log(p.age)
    p.eating()
    
    export {}
    

    2. 类的继承

    1. 面向对象的其中一大特性就是继承,继承不仅仅可以减少我们的代码量,也是多态的使用前提。
    2. 我们使用extends关键字来实现继承,子类中使用super来访问父类。
    3. 我们来看一下Student类继承自Person:
    • Student类可以有自己的属性和方法,并且会继承Person的属性和方法;
    • 在构造函数中,我们可以通过super来调用父类的构造方法,对父类中的属性进行初始化;
    class Person {
      name: string = ""
      age: number = 0
    
      eating() {
        console.log("eating")
      }
    }
    
    class Student extends Person {
      sno: number = 0
    
      studying() {
        console.log("studying")
      }
    }
    
    class Teacher extends Person {
      title: string = ""
    
      teaching() {
        console.log("teaching")
      }
    }
    
    const stu = new Student()
    stu.name = "coderwhy"
    stu.age = 10
    console.log(stu.name)
    console.log(stu.age)
    stu.eating()
    

    使用super的继承

    class Person {
      name: string
      age: number
    
      constructor(name: string, age: number) {
        this.name = name
        this.age = age
      }
    
      eating() {
        console.log("eating 100行")
      }
    }
    
    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")
      }
    }
    
    const stu = new Student("why", 18, 111)
    console.log(stu.name)
    console.log(stu.age)
    console.log(stu.sno)
    
    stu.eating()
    
    export {}
    
    
    

    类的多态

    class Animal {
      action() {
        console.log("animal action")
      }
    }
    
    class Dog extends Animal {
      action() {
        console.log("dog running!!!")
      }
    }
    
    class Fish extends Animal {
      action() {
        console.log("fish swimming")
      }
    }
    
    class Person extends Animal {
    
    }
    
    // animal: dog/fish
    // 多态的目的是为了写出更加具备通用性的代码
    function makeActions(animals: Animal[]) {
      animals.forEach(animal => {
        animal.action()//执行的是重写之后的方法
      })
    }
    //其实对于我们makeActions里面的参数中的每个元素来说,
    //就是我们看起来是相同的类型,都是animal类型,
    //但是在真正执行我们方法的时候,他们表现出来的形态是不一样的,就是我也是执行action的时候,执行的是各自的action
    
    makeActions([new Dog(), new Fish(), new Person()])
    

    3. 类的成员修饰符

    1. 在TypeScript中,类的属性和方法支持三种修饰符: public、private、protected
      • public 修饰的是在任何地方可见、公有的属性或方法,默认编写的属性就是public的;其他地方都能访问。
      • private 修饰的是仅在同一类中可见、私有的属性或方法;实例不能访问privita属性。
      • protected 修饰的是仅在类自身及子类中可见、受保护的属性或方法;
    2. public是默认的修饰符,也是可以直接访问的,我们这里来演示一下protected和private。
    class Person {
      private name: string = ""
    
      // 封装了两个方法, 通过方法来访问name
      getName() {
        return this.name
      }
    
      setName(newName) {
        this.name = newName
      }
    }
    
    const p = new Person()
    console.log(p.getName())
    p.setName("why")
    
    export {}
    

    protected

    // protected: 在类内部和子类中可以访问
    
    class Person {
      protected name: string = "123"
    }
    
    class Student extends Person {
      getName() {
        return this.name
      }
    }
    
    const stu = new Student()
    console.log(stu.getName())
    
    export {}
    

    4. 只读属性readonly

    如果有一个属性我们不希望外界可以任意的修改,只希望确定值后直接使用,那么可以使用readonly:
    只读属性在constructor中赋值的比较多。只读属性是可以在constructor中赋值的。

    class Person {
      // 1.只读属性是可以在构造器中赋值, 赋值之后就不可以修改
      // 2.属性本身不能进行修改, 但是如果它是对象类型, 对象中的属性是可以修改
      readonly name: string
      age?: number
      readonly friend?: Person
      constructor(name: string, friend?: Person) {
        this.name = name
        this.friend = friend
      }
    }
    
    const p = new Person("why", new Person("kobe"))
    console.log(p.name)
    console.log(p.friend)
    
    // 不可以直接修改friend
    // p.friend = new Person("james")
    if (p.friend) {
      p.friend.age = 30
    } 
    
    // p.name = "123"
    
    

    5.getters/setters

    在前面一些私有属性我们是不能直接访问的,或者某些属性我们想要监听它的获取(getter)和设置(setter)的过程,这个时候我们可以使用存取器。

    class Person {
      private _name: string
      constructor(name: string) {
        this._name = name
      }
    
      // 访问器setter/getter
      // setter
      set name(newName) {
        this._name = newName
      }
      // getter
      get name() {
        return this._name
      }
    }
    
    const p = new Person("why")
    p.name = "coderwhy"
    console.log(p.name)
    
    

    6. 静态成员

    1. 前面我们在类中定义的成员和方法都属于对象级别的, 在开发中, 我们有时候也需要定义类级别的成员和方法。就是直接通过类来获取它的方法和属性。
    2. 在TypeScript中通过关键字static来定义:
    // class Person {
    //   name: string = ""
    //   age: number = 12
    // }
    
    // const p = new Person()
    // p.name = "123"
    
    class Student {
      static time: string = "20:00"
    
      static attendClass() {
        console.log("去学习~")
      }
    }
    
    console.log(Student.time)
    Student.attendClass()
    
    
    

    7. 抽象类abstract

    1. 我们知道,继承是多态使用的前提。
    • 所以在定义很多通用的调用接口时, 我们通常会让调用者传入父类,通过多态来实现更加灵活的调用方式。
    • 但是,父类本身可能并不需要对某些方法进行具体的实现,所以父类中定义的方法,,我们可以定义为抽象方法。
    1. 什么是 抽象方法? 在TypeScript中没有具体实现的方法(没有方法体),就是抽象方法。
    • 抽象方法,必须存在于抽象类中;
    • 抽象类是使用abstract声明的类;

    抽象类有如下的特点:

    • 抽象类是不能被实例的话(也就是不能通过new创建)
    • 抽象方法必须被子类实现,否则该类必须是一个抽象类;


      image.png
    
    function makeArea(shape: Shape) {
      return shape.getArea()
    }
    
    
    abstract class Shape {
      abstract getArea(): number
    }
    
    
    class Rectangle extends Shape {
      private width: number
      private height: number
    
      constructor(width: number, height: number) {
        super()
        this.width = width
        this.height = height
      }
    
      getArea() {
        return this.width * this.height
      }
    }
    
    class Circle extends Shape {
      private r: number
    
      constructor(r: number) {
        super()
        this.r = r
      }
    
      getArea() {
        return this.r * this.r * 3.14
      }
    }
    
    const rectangle = new Rectangle(20, 30)
    const circle = new Circle(10)
    
    console.log(makeArea(rectangle))
    console.log(makeArea(circle))
    // makeArea(new Shape())
    
    // makeArea(123)
    // makeArea("123")
    
    
    

    6. 类的类型

    类本身也是可以作为一种数据类型的:
    把一个类作为类型,然后放到某一个位置,这个就叫做类的类型.

    class Person {
      name: string = "123";
      eating() {}
    }
    
    const p = new Person();
    
    const p1: Person = {
      name: "why",
      eating() {},
    };
    //p1的类型是Person的话,
    //那必须要有name属性和eating方法,必须和Person里面的实例成员保持一致
    
    function printPerson(p: Person) {
      console.log(p.name);
    }
    
    printPerson(new Person());
    printPerson({ name: "kobe", eating: function () {} });
    //这两个等价
    export {};
    
    

    相关文章

      网友评论

          本文标题:TypeScript类的使用(六)

          本文链接:https://www.haomeiwen.com/subject/beqvortx.html