ts入门笔记-02>类、构造函数、接口.....

838 阅读5分钟

类的简介

// 使用class关键字定义一个类

/**
 *   对象中包含两个部分:
 *        属性
 *        方法
 * 
*/

class Person{

  /**
   *   直接定义的属性是实例属性,需要通过对象的实例去验访问:
   *      const per = new Person();
   *      per.name
   *   使用static开头的属性是静态属性(类属性),可以直接通过类去使用
   *      person.age
   *   
   *   readonly开头的属性表示一个只读的属性
  */

  // readonly name: string = "随悟空";

  // 在属性前使用static关键字可以定义类属性(静态属性)
  // static readonly age: number = 18


  // 定义实例属性
  name = '随悟空'
  age = 22

  /**
   *  定义方法
   * 
   *  如果方法以satatic开头则方法就是类方法,可以直接通过类去调用
   * 
   * */
  sayHello() {
    console.log("hello,你好");
    
  }
}

const per = new Person()
console.log(per);


构造函数


class Dog{
  name: string;
  age: number;

  // constructor 被称为构造函数
  // 构造函数会再对象被创建时调用
  constructor(name: string, age: number) {
    /**
     * 在实例方法中,this就表示当前的实例
     * 在构造函数中当前对象就是当前新建的哪个对象
     * 可以通过this向新建的对象中添加属性
    */
    this.name = name;
    this.age = age;
  }

  bark() {
    // alert("汪汪汪");
    // 在方法中可以通过this来表示当前调用方法的对象
    console.log(this.name)
  }
}

const dog = new Dog('小黑', 44);
const dog2 = new Dog('小白', 14);

console.log(dog.bark);
console.log(dog2.bark);

继承

(function() {
  // 定义一个Animal类
  class Animal{
    name: string;
    age: number;
    constructor(name: string, age: number) {
      this.name = name;
      this.age = age;
    }

    sayHello() {
      console.log("动物在叫~");
    }
  }
  /**
   * Dog extends Animal 
   *  - 此时Animal被称为父类,Dog被称为子类
   *  - 使用继承后,子类将会拥有父类的所有属性和方法
   *  - 通过继承可以将多个类中共同的代码写在一个父类中,
   *        这样只要写一次即可让所有的子类都同时拥有父类中的属性和方法
   *        如果需要在子类中添加一些父类没有的属性和方法直接添加就行,
   *  - 如果子类中添加了和父类相同的方法,则子类方法会覆盖掉父类的方法
   *        这种子类覆盖掉父类方法的形式,我们称为方法重写
   *        
  */
  class Dog extends Animal {
    sayHello() {
      console.log("汪汪汪");
      
    };
    run() {
      console.log("狗崽跑")
    }
  }

  class Cat extends Animal {
    sayHello() {
      console.log("喵喵喵");
      
    };
  }

  const dog = new Dog('旺财',25);
  console.log(dog);
  dog.sayHello()
  
  const cat = new Cat('咪咪', 12)
  console.log(cat);
  cat.sayHello()
  dog.run()

})()

super

(function() {
  class Animal {
    name: string;

    constructor(name: string){
      this.name = name;
    }
    sayhello() {
      console.log("动物在叫")
      
    }
  }

  class Dog extends Animal {
    age: number;
    constructor(name: string, age: number) {
      // 如果子类中写了构造函数,在子类构造函数中必须对父类的构造函数进行调用

      super(name); // 调用父类的构造函数
      this.age = age;
    }

    sayhello() {
      // 在类的方法中 supper就表示当前类的父类
      super.sayhello()
    }
  }

  let dog = new Dog("旺财", 22)
  dog.sayhello()
  console.log(dog)
 
})()

抽象类

(function() {
  
  /**
   * 定义一个抽象类
   *   抽象类就是专门被其它类继承的类,没有办法在创建实例对象,它里面可以添加抽象方法
   * 
   * */ 
  abstract class Animal {
    name: string;

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

    /**
     * 定义一个抽象方法
     *   抽象方法使用abstract开头,没有方法体,没有返回值
     *   抽象方法只能定义在抽象类中,子类必须对抽象方法进行重写
     * 
     * 
    */
    abstract sayhello(): void
  }

  class Dog extends Animal {

    sayhello() {
      console.log("汪汪汪");
      
    }
  }
  class Cat extends Animal {

    sayhello() {
      console.log("喵喵喵");
      
    }
  }

  let dog = new Dog("旺财")
  dog.sayhello()
  console.log(dog)
  
})()

接口

(function() {
  // 描述一个对象的类型
  type myTytpe = {
    name: string,
    age: number
  };

  // const obj: myTytpe = {
  //   name: "sss",
  //   age: 15
  // }

  /**
   * 接口用来定义一个类的结构,用来定义一个类中应该包含哪些属性和方法
   *    同时接口也可以当成类型声明去使用
   * 
   * 
  */
  interface myInterface{
    name: string;
    age: number;
  }

  interface myInterface {
    gender: string
  }

  // const obj: myInterface = {
  //   name: "sss",
  //   age: 15,
  //   gender: "人妖"
  // } 

  /**
   * 接口可以在定义类的时候去限制类的结构
   *   接口中的所有属性和方法都不能有实际的值
   *   接口中只定义对象的结构,而不考虑实际的值
   *      在接口中所有的方法都是抽象的方法
   * 
  */

  interface myInter{
    name: string;
    sayhello():void;
  }

  /**
   *  定义类时,可以使用类去实现一个接口、
   *    实现接口就是使用类满足接口的要求
   * 
   * 
  */

  class myClass implements myInter{
    name: string;
    constructor(name:string){
      this.name = name;
    }
    sayhello() {
      console.log('大家好~~');
      
    }
  }

})()

属性的封装

(function(){
  // 定义一个表示人的类
  class Person{
    /** 
     * TS可以在属性前添加属性的修饰符
     * 
     *  public 修饰的属性可以在任意位置访问(修改) 默认值
     *  private 私有属性, 私有属性只能在类内部进行访问(修改)
     *    - 通过在类中添加方法使得私有属性可以被外部访问
     * 
     *  protected 受保护的属性,只能在当前类和当前类的子类中访问(修改)
     * */

    private _name: string;
    private _age: number;

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

    /**
     * getter方法用来读取属性
     * setter方法用来设置属性
     *    - 它们被称为属性的存取器
     * 
    */

    // // 定义方法 来获取name属性
    // getName() {
    //   return this._name;
    // }

    // // 定义方法 用来设置name属性
    // setName(value:string) {
    //   this._name = value;
    // }

    // getAge() {
    //   return this._name;
    // }
    // setAge(value: number) {
    //   // 判断年龄是否合法
    //   if(value >= 0) {
    //     this._age = value;
    //   }
    // }

    // TS中设置getter方法的形式
    get name() {
      console.log('get name() 执行了');
      
      return this._name;
    }

    // TS中设置setter方法形式
    set name(value: string) {
      this._name = value
    }

    get age() {
      return this._age;
    }

    set age(value: number) {
      if(value >= 0) {
        this._age = value;
      }
    }

  }

  const per = new Person('金蝉子', 100);

  /**
   * 现在属性是在对象中设置的,属性可以任意的被修改
   *   属性可以任意被修改将会导致对象中的数据变得非常不安全
   * 
  */

  per.name = "猪八戒";
  per.age = 118;

  console.log(per.name);
  
  
  class A{
    protected num: number;

    constructor(num: number) {
      this.num = num;
    }
  }

  class B extends A{

    test() {
      console.log(this.num);
      
    }
  }

  const b = new B(123);
  // b.num = 33

  class C{
    // 可以直接将属性定义在构造函数中
    constructor(public name:string, public age: number) {

    }
  }

  const c = new C('sss',55)
})()

泛型

/**
 *   在定义函数或是类时,如果遇到类型不明确就可以使用泛型
 * 
*/
function fn<T>(a:T):T{
  return a;
}

// 可以直接调用具有泛型的函数
fn(10); // 不指定泛型,TS可以自动对泛型进行判断
fn<string>("sss"); // 指定泛型

// 泛型可以同时指定多个
function fn2<T,K>(a:T, b:K): T {
  console.log(b)
  return a;
};
fn2<number, string>(123,  'hello');

interface Inter{
  length: number;
}

// T extents Inter 表示泛型T 必须是Inter实现类(子类)
function fn3<T extends Inter>(a: T):number{
  return a.length;
}

fn3({length: 10})

class MyClass<T>{
  name: T;
  constructor(name:T) {
    this.name = name;
  }
}

const mc = new MyClass('悟能');