03-TS的类

200 阅读6分钟

01-类

//! 类 可以理解为模板,通过模板来实例化对象
//! 面向对象的编程思想
(() => {
  //* ts中的类的定义和使用
  class Person {
    //* 定义属性
    name: string;
    age: number;
    //* 定义构造函数:为了将来实例化对象的时候,可以直接对对象的值进行初始化
    constructor(name: string, age: number) {
      this.name = name;
      this.age = age;
    }
    //* 定义实例方法
    say(str: string) {
      console.log(`我是${this.name},今年${this.age}`, str);
    }
  }
  //* ts中使用类
  const person = new Person("不好也行", 15);
  person.say("你好");
})();

02-继承

//! 继承 类与类之间的关系
//! 继承后类与类之间的叫法
/**
 * ? A继承了B这个类,那么A叫子类,B叫基类
 * ? 子类---->派生类
 * ? 基类---->超类(父类)
 * ? 一旦发生了继承关系,就出现了父子类的关系
 */
(() => {
  //定义一个父类
  class Person {
    //定义属性
    name: string; //名字
    age: number;
    //定义构造函数
    constructor(name: string, age: number) {
      this.name = name;
      this.age = age;
    }
    //定义实例方法
    say(str: string) {
      console.log(`我是${this.name},我${this.age}岁了${str}`);
    }
  }

  // 定义一个子类
  class Son extends Person {
    constructor(name: string, age: number) {
      //! 调用父级的构造函数,用super
      super(name, age);
    }
    //可以调用父类中的方法
    say() {
      //console.log("我是子级调用了父级");
      super.say("哈哈");
    }
  }
  const person = new Person("不好也行", 15);
  person.say("father");
  const son = new Son("子级", 15);
  son.say();

  //! 类和类之间如果有继承关系 使用extends
  //! 子类如果调用父级的构造函数用super的方法,如果调用父级的方法也用super
  //! 子类中可以重写父类的方法
})();

03-多态

//! 多态 父类型的引用指向了子类型的对象
//! 不同类型的对象针对相同的方法,产生了不同的行为
(() => {
  //定义一个父类
  class Animal {
    //* 定义一个属性
    name: string;
    //* 定义一个构造函数
    constructor(name: string) {
      //* 更新属性值
      this.name = name;
    }
    //* 实例化
    run(distance: number = 0) {
      console.log(`跑了${distance}米 `, this.name);
    }
  }
  //定义一个子类
  class Dog extends Animal {
    constructor(name: string) {
      //* 调用父级的构造函数,实现子类中属性的初始化
      super(name);
    }
    //* 实例化
    run(distance: number = 5) {
      console.log(`跑了${distance}米 `, this.name);
    }
  }
  //再定义一个子类
  class Pig extends Animal {
    constructor(name: string) {
      //* 调用父级的构造函数,实现子类中属性的初始化
      super(name);
    }
    //* 实例化
    run(distance: number = 10) {
      console.log(`跑了${distance}米 `, this.name);
    }
  }
  //实例化父级
  const ani: Animal = new Animal("动物");
  ani.run();
  //实例化子级
  const dog: Dog = new Dog("小狗子");
  dog.run();
  //实例化子级
  const pig: Pig = new Pig("小猪");
  pig.run();

  console.log("===============");

  //* 父子关系,此时用父类类型创建子类的对象
  const dog1: Animal = new Dog("小狗子1");
  dog1.run();
  const pig1: Animal = new Pig("小猪1");
  pig1.run();

  console.log("===============");
  
  function showRun(ani: Animal) {
    ani.run();
  }
  showRun(dog1);
  showRun(pig1);
})();

04-修饰符

//! 修饰符
/**
 * *类中成员的修饰符
 * *主要是描述类中的成员(属性,构造函数,方法)的可访问性
 * *类中的成员都有自己默认的访问修饰符,public
 * ! public---公共,是类中成员默认的修饰符,代表的是公共的,任何位置都可以访问类中的成员
 * ! private---私有 是私有的,类中的成员如果用private来修饰,外部是无法访问的,当然子类中也无法访问该成员数据
 * ! protected---受保护的,只能子类访问,类中的成员如果用protected来修饰,外部是无法访问的
 */

(() => {
  class Person {
    //? 属性 public 修饰了属性成员
    //public name: string;
    //? 属性 private 修饰了属性成员
    //private name: string;
    //? 属性 protected 修饰了属性成员
    protected name: string;
    public constructor(name: string) {
      this.name = name;
    }
    public set() {
      console.log("嗯", this.name);
    }
  }

  class son extends Person {
    constructor(name: string) {
      super(name);
    }
    play() {
      console.log("玩", this.name);
    }
  }
  const person = new Person("大石窝");
  //? 类的外部可以访问类中的属性成员
  // console.log(person.name);
  // person.set();
  //? 
  const son1 = new son("kk");
  son1.play();
  
})();

05-readonly修饰符

// ! readonly 修饰符
/**
 * * 是一个关键字
 * * 对类中的成员进行修饰
 * * 被修饰的属性成员,不能在外部进行修改了
 * ! 构造函数中可以对只读的属性进行修改
 * ! 如果构造函数中没有任何参数,类型的属性成员已经经过 readonly 修饰了,那么外部也不可以对属性进行修改
 * ! 构造函数中可以用readonly进行修饰,一旦修饰了该类中就有这个只读的成员属性了,外部可以访问但是不能修改
 * ! 构造函数可以用 public,private,protected进行修饰, 无论是哪个进行修饰,该类中都会自动的添加这么一个属性成员
 */
(() => {
  //! readonly 修饰类中属性
  class Person {
    // 初始值
    readonly name: string;
    constructor(name: string) {
      this.name = name;
    }
    say() {
      console.log("你好", this.name);
      //? 类中的普通方法中也不能修改 readonly 修饰的成员属性
      //this.name='??'
    }
  }
  const person = new Person("不好也行");
  console.log(person);
  console.log(person.name);
  // person.name = "??????/";
  // console.log(person.name);
  person.say();

  console.log("-----------------------------------------");

  //! readonly 修饰类中的构造函数中的参数
  class S {
    //? 构造函数中的name参数,一旦使用readonly进行修饰后,该name可以叫做参数属性
    //? 构造函数中的name参数,一旦使用readonly进行修饰后,那么S中就有一个name的属性成员
    //! 构造函数中的name参数,一旦使用readonly进行修饰后,外部也是无法修改内部name的属性值的
    constructor(readonly name: string) {
      this.name = name;
    }
    //? 构造函数中的name参数,一旦使用public进行修饰后,那么S中就有一个公共的name的属性成员
    // constructor(public name: string) {
    //   this.name = name;
    // }
    //? 构造函数中的name参数,一旦使用private进行修饰后,那么S中就有一个私有的name的属性成员
    // constructor(private name: string) {
    //   this.name = name;
    // }
    //? 构造函数中的name参数,一旦使用protected进行修饰后,那么S中就有一个受保护的name的属性成员
    //? 只能在本类或派生类中使用
    // constructor(protected name: string) {
    //   this.name = name;
    // }
  }
  const s = new S("不好也行A");
  console.log(s);
  console.log(s.name);
})();

06-存取器

//! 存取器
/**
 * * 让我们可以有效的控制对 对象中成员的访问,
 * * 通过 getters 和 setters 来进行操作
 */
(() => {
  // 外部可以传入姓氏和名字数据,同时使用set和get控制姓名的数据,外部也可以进行修改的操作
  class Parson {
    firstName: string; //姓氏
    lastName: string; //名字
    constructor(firstName: string, lastName: string) {
      this.firstName = firstName;
      this.lastName = lastName;
    }
    //姓名的成员属性,外部可以进行修改和访问
    //! 读取器---负责读取数据
    get fullName() {
      console.log("get中......");
      //* 姓名====> 姓氏和名字的拼接
      return this.firstName + "_" + this.lastName;
    }
    //! 设置器---负责设置数据(修改)
    set fullName(val) {
      console.log("set中......");
      console.log(val);

      //* 姓名====> 姓氏和名字取到,重新赋值和firstName和lastName
      let name = val.split("_");
      this.firstName = name[0];
      this.lastName = name[1];
    }
  }
  const person: Parson = new Parson("1", "2");
  //获取
  console.log("get person: ", person.fullName);
  //设置
  person.fullName = "11111_2";
  //console.log("set person: ", person.fullName);
})();

07-静态成员

//! 静态成员
/**
 *  * 在类中通过static修饰的属性或方法
 *  * 要么就是静态的属性及静态的方法,也称之为:静态成员
 *  ! 静态成员在是用的时候是通过类名.的这种方法来调用的
 */
(() => {
  class Person {
    //? 静态属性
    //? 类中默认有一个内置的name属性,所以此时会报错
    static name1: string = "????";
    //name1: string;
    //? 构造函数不能通过static来修饰
    constructor(name: string) {
      /**
       * ? 此时this是实例对象,name1是静态属性
       * ? 不能通过实例对象直接调用静态属性来使用
       */
      //this.name1 = name1;
    }
    //? 静态方法
    static say() {
      console.log("111111111");
    }
  }
  //const person: Person = new Person();
  //? 通过实例对象来调用的属性(实例属性)
  //console.log(person.name1);
  //? 通过实例对象调用的方法(实例方法)
  //person.say();
  //? 通过类名.静态属性的方式来访问该成员数据
  console.log(Person.name1);
  //? 通过类名.静态属性的方式来设置该成员数据
  Person.name1 = "456465";
  console.log(Person.name1);
  //? 通过类名.静态属性的方式来调用内部的静态的方法
  Person.say();
})();

08-抽象类

//! 抽象类
/**
 * * 包含抽象的方法(抽象方法一般没有任何的具体内容实现)
 * * 也可以包含实例方法
 * ! 抽象类不能被实例化
 * * 作用:为了让子类进行实例化及实现内部的抽象方法
 * ! 目的或者作用最终都是为子类服务的
 */
(() => {
  //定义抽象类
  abstract class Animal {
    //? 抽象属性
    //abstract name: string;
    //? 抽象方法
    //? 抽象的方法不能有具体的实现
    // abstract eat() {
    //   console.log("就是吃");
    // }
    abstract eat(): any;
    //? 实例方法
    say() {
      console.log("说话啊");
    }
  }
  // 定义一个子类(派生类)
  class Dog extends Animal {
    //name: string = "54";
    //? 重新实现抽象类中的方法
    //? 此时这个方法就是Dog类的实例方法
    eat() {
      console.log("跪着吃");
    }
  }
  // 实例化dog的对象
  const dog: Dog = new Dog();
  dog.eat();
  //? 调用的是抽象类中的实例方法
  dog.say();
  // console.log(dog.name);

  //?不能实例化抽象类的对象
  //const animal:Animal = new Animal();
})();