TypeScript基础入门第三弹——面向对象 | 青训营笔记

45 阅读5分钟

这是我参加「第四届青训营 」笔记创作活动的第八天。

1. 什么是面向对象

面向对象的编程语言是写程序所有的操作都是通过对象操作,所以叫面向对象。

2. 类

定义了对象是什么样子,相当于人的DNA,类可以理解为是对象的模型

3. 创建类

  1. 创建tsconfig.json文件并进行配置
{
  "compilerOptions": {
    "module": "ES2015",
    "target": "ES2015",
    "sourceMap": true,
    "outDir": "./dist"
  },
  "include": ["./src/**/*"]
}

  1. 创建src文件夹并创建文件01-class.ts
//使用class关键字定义一个类

class Person {
  //定义实例属性
  name: string = "su";
  //定义类属性/静态属性
  static age: number = 18;
  //readonly只读不改
  readonly stu: string = "math";
  //static和readonly可以一起用

  //定义方法
  sayHello() {
    console.log("hi");
  }
}
const per = new Person();
console.log(per);
console.log(per.name);
console.log(Person.age);
alert("a");
per.sayHello();

3.在part3创建index.html文件,并引入js,然后打开 目录结构 image.png

4. 构造函数

class Dog {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
  break() {
    console.log(this.name);
    
  }
}
const dog = new Dog("xiaohei", 4);
console.log(dog);
dog.break()

5. 继承

super关键字

//立即执行函数避免变量发生冲突
(function () {
  class Animal {
    name: string;
    age: number;
    constructor(name: string, age: number) {
      this.name = name;
      this.age = age;
    }
    break() {
      console.log("动物在叫");
    }
  }
  class Dog extends Animal {
    run() {
      console.log("pao");
    }
    //子类添加父类相同方法,会覆盖
    break() {
      console.log("wang在叫");
    }
  }
  class Cat extends Animal {
    color:string;
    //若添加新的属性必须先继承父类的,用super关键字
    constructor(name: string, age: number,color:string){
      super(name,age);
      this.color=color
    }
    break() {
      //引用父类
      super.break();
    }
  }
  const dog = new Dog("xiaohei", 4);
  console.log(dog);
  alert(dog.name);
  dog.break();
  dog.run();
  const cat = new Cat("mao", 3,"black");
  console.log(cat);
  cat.break();
})();

6. 抽象类

//立即执行函数避免变量发生冲突
(function () {
  //抽象类不能用来创建对象,就是拿来当父类使用。abstract
  abstract class Animal {
    name: string;
    age: number;
    constructor(name: string, age: number) {
      this.name = name;
      this.age = age;
    }
    //抽象类可以创建抽象方法
    //抽象方法只能在抽象类中,子类必须对抽象方法进行重写
    abstract break(): void;
  }
  class Dog extends Animal {
    run() {
      console.log("pao");
    }
    //子类添加父类相同方法,会覆盖
    break() {
      console.log("wang在叫");
    }
  }

  const dog = new Dog("xiaohei", 4);
  console.log(dog);
  alert(dog.name);
  dog.break();
  dog.run();
})();

7. 接口:定义规范,对类进行限制

  • 接口用来定义一个类结构,与上面的效果相同,定义一个类中应该包含哪些属性和方法,同时接口也可以当成类型声明取使用
  • 接口可以重复声明,多个接口合并
  • 接口可以在定义类的时候限制类的结构
  • 类口中的所有属性不能有实际的值,而不考虑实际值
  • 接口里面都是抽象方法
(function () {
  //描述一个对象的类型
  type User = {
    name: string;
    age: number;
  };
  const obj: User = {
    name: "ss",
    age: 19,
  };

  //   接口用来定义一个类结构,与上面的效果相同,定义一个类中应该包含哪些属性和方法,同时接口也可以当成类型声明取使用
  //接口可以重复声明,多个接口合并
  //接口可以在定义类的时候限制类的结构
  //类口中的所有属性不能有实际的值,而不考虑实际值
  interface myInterface {
    name: string;
    age: number;
  }
  interface myInterface {
    gender: string;
    sayHello(): void; //抽象方法
  }
  const obj1: myInterface = {
    name: "ss",
    age: 19,
    gender: "female",
    sayHello() {
      console.log("hhh");
    },
  };
})();

定义类时,可以使类取实现一个接口。关键字:implements

  //定义类时,可以使类取实现一个接口。关键字:implements,使类满足接口的要求
  class Mycl implements myInterface {
    name: string;
    age: number;
    gender: string;
    constructor(name: string, age: number, gender: string) {
      this.age = age;
      this.name = name;
      this.gender = gender;
    }
    sayHello() {
      console.log("hahah");
    }
  }
})();

8. 封装:让属性更加安全

  • public修饰的属性可以在任意位置访问(默认值)
  • private修饰的属性只能在类内部进行访问
  • 因为私有,所有外部拿不到,就需要定义一个方法可以获取内部属性
//立即执行函数避免变量发生冲突
(function () {
  class Person {
    name: string;
    age: number;
    //public修饰的属性可以在任意位置访问(默认值)
    //private修饰的属性只能在类内部进行访问
    public _sex: string;
    private _course: string;
    constructor(name: string, age: number, sex: string, course) {
      this.name = name;
      this.age = age;
      this._sex = sex;
      this._course = course;
    }
    //
    //定义方法主动权在我们手上,比如可以设一个判断修改的值是否合法,让代码更健壮
    //定义一个方法可以获取内部属性
    getName() {
      return this.name;
    }
    //定义一个方法可以修改内部属性
    setName(value: string) {
      //可以设一个判断修改的值是否合法
      this._sex = value;
    }
  }

  const per = new Person("xiaohei", 4, "female", "math");
  console.log(per);
  //数据可以任意修改,不安全
  per.age = -3;
  per._sex = "male";
  // per._course = "chinese"; //会报错,属性“_course”为私有属性,只能在类“Person”中访问。
  console.log(per);
  console.log(per.getName());
  per.setName("nan");
})();

TS中设置getter,setter方法的方式

//立即执行函数避免变量发生冲突
(function () {
  class Person {
    name: string;
    age: number;
    //public修饰的属性可以在任意位置访问(默认值)
    //private修饰的属性只能在类内部进行访问
    public _sex: string;
    private _course: string;
    constructor(name: string, age: number, sex: string, course) {
      this.name = name;
      this.age = age;
      this._sex = sex;
      this._course = course;
    }
    //TS中设置getter方法的方式
    get course() {
      return this._course;
    }
    //定义一个setter方法可以修改内部属性
    set course(value: string) {
      this._course = value;
    }
  }
  const per = new Person("xiaohei", 4, "female", "math");
  //使用习惯一样
  console.log(per.course);
  per.course = "ha";
  console.log(per.course);
})();

protected受包含的属性,只能在当前类和当前类的子类中访问

(function () {
  class A {
    private num: number;
    //protected受包含的属性,只能在当前类和当前类的子类中访问
    protected age: number;
    constructor(num: number, age: number) {
      this.num = num;
      this.age = age;
    }
  }
  class B extends A {
    test() {
      //   console.log(this.num); //属性“num”为私有属性,只能在类“A”中访问。
      console.log(this.age);
    }
  }
})();

简便写法

//语法糖
(function () {
  class C {
    //可以直接将属性定义在构造函数中
    constructor(public name: string, public age: number) {}
  }
  const c = new C("wh", 80);
  //等价于
   class C {
    ame: stringage: number
    constructor(name: string, age: number) {
    this.name=name;
    this.age=age;
    }
  }
  const c = new C("wh", 80);
})();
})();

泛型

在定义函数或者类时,遇到类型不明确就可以使用泛型

// function fn(a: number): number {
//   return a;
// }
//在定义函数或者类时,遇到类型不明确就可以使用泛型
function fn<T>(a: T): T {
  return a;
}
//可以直接调用具有泛型的函数
let s = fn(10); //不指定,TS自动对类型进行推断
let b = fn<string>("hello"); //指定泛型

//泛型可以同时指定多个
function fn2<T, K>(a: T, b: K): T {
  return a;
}
fn2(12, "ok");
fn2<number, string>(12, "ok");

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

//类中使用
class Myclass<T> {
  name: T;
  constructor(name: T) {
    this.name = name;
  }
}
const mc = new Myclass<string>("wh");