四、面向对象

郁子大约 6 分钟约 1653 字笔记TypeScript尚硅谷李立超

(一)面向对象简介

  • 程序中所有的操作都需要通过对象来完成。一切操作都要通过对象,即面向对象
    • 操作浏览器 —— window 对象
    • 操作网页 —— document 对象
    • 操作控制台 —— console 对象
  • 计算机程序的本质是对现实事物的抽象,抽象的反义词是具体
    • 如:照片是对一个具体的人的抽象,汽车模型是对一辆具体的车的抽象
  • 在程序中所有的对象都被分成了两个部分:数据功能
    • 如:人的姓名、性别、年龄、身高、体重等属于数据,人可以说话、走路、吃饭、睡觉等属于人的功能
    • 数据在对象中被称为属性,功能被称为方法,在程序中一切皆是对象

(二)类(class)

  • 要想面向对象、操作对象,首先要拥有对象,要创建对象,必须要先定义类
  • 类可以理解为对象的模型,在程序中可以根据类创建指定类的对象

1.定义类

class 类名 {
  属性名: 类型;

  constructor(参数: 类型) {
    this.属性名 = 参数;
  }

  方法名() {
    ......
  }
}

/* =============== 示例 =============== */
class Person {
  name: string;
  age: number;

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

  sayHello() {
    console.log("Hello, TS");
  }
}

2.实例属性

  • 直接定义的属性叫实例属性
  • 需要通过对象的实例去访问
class Person {
  // 定义实例属性
  name: string = "Alice";
}

// 定义对象的实例
const person = new Person();
// 访问实例属性
console.log(person.name);

3.静态属性(类属性)

  • 使用 static 定义的属性叫静态属性
  • 可以直接通过类名去访问
class Person {
  // 定义静态属性
  static age: number = 20;
}

// 定义对象的实例
const person = new Person();
// 访问静态属性
console.log(Person.age);

4.只读属性

  • 使用 readonly 定义的不可修改的属性叫只读属性
  • 需要通过对象的实例去访问
class Person {
  // 定义只读属性
  readonly name: string = "Alice";
  static readonly age: number = 20; // static应先声明
}

// 定义对象的实例
const person = new Person();
// 修改只读属性
person.name = "Tom"; // 报错
person.age = 30; // 报错
// 访问只读属性
console.log(person.name, person.age);









 
 


5.方法

  • 直接声明的方法叫实例方法
  • 使用 static 声明的方法叫静态方法(类方法)
class Person {
  name: string = "Alice";
  age: number = 20;

  // 定义方法
  sayHello() {
    console.log("Hello, TS");
  }
  static sayHello2() {
    console.log("Hello, TS");
  }
}

// 定义对象的实例
const person = new Person();
// 调用方法
person.sayHello();
Person.sayHello2();

(三)构造函数和 this

  • constructor 被称为构造函数,会在对象创建时自动调用
  • 在构造方法中,当前对象就是当前 new 新建的对象,可以通过 this 向新建对象添加属性
  • 在实例方法中,this 表示当前的实例,可以通过 this 来表示当前调用方法的对象
class Dog {
  name: string;
  age: number;

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

  bark() {
    alert("汪汪汪~");
    console.log(this);
  }
}

const dog1 = new Dog("旺财", 3);
const dog2 = new Dog("富贵", 5);
console.log(dog1, dog2);
dog1.bark();
dog2.bark();

(四)继承

  • 使用继承后,子类将拥有父类中的所有方法
  • 语法:class 子类 extends 父类
  • 可以将多个类中的共有代码写在一个父类中
  • 子类中定义和父类相同的方法,则子类方法会覆盖父类方法 —— 重写
class Animal {
  name: string;
  age: number;

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

  sayHello() {
    console.log("动物在叫~");
  }
}

class Dog extends Animal {
  run() {
    console.log(`${this.name}在跑`);
  }
}

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

const dog = new Dog("旺财", 5);
const cat = new Cat("富贵", 3);
console.log(dog);
console.log(cat);
dog.sayHello();
cat.sayHello();
dog.run();

(五)super 关键字

  • 在子类的方法中,super 就表示当前类的父类
  • 如果子类声明了构造函数,则必须在所有 this 操作前调用父类的构造函数
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() {
    super.sayHello();
  }
}

const dog = new Dog("旺财", 5);
console.log(dog);
dog.sayHello();
















 




 






(六)抽象类

  • abstract 定义的类叫抽象类
  • 抽象类和其他类区别不大,只是不能用来创建对象,是专门用来被继承的类
  • 抽象类中可以添加抽象方法
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 {} // 报错

const dog = new Dog("旺财", 5);
dog.sayHello();

const animal = new Animal("狗"); // 报错





















 




 

(七)接口

  • 接口用来定义一个类(对象)结构,定义一个类中应该包含哪些属性
  • 接口也可以当做类型声明使用
    • type 不能重复声明,interface 可以
    • 定义多个同名 interface 会把各属性作合并
  • 接口可以在定义类时限制类的结构
    • 接口中的所有属性都不能有实际的值
    • 接口只定义对象的结构,而不考虑实际值
  • 定义类时可以使类去实现一个接口
    • 实现接口就是使类满足接口的要求
// 描述一个对象的类型
type myType = {
  name: string;
  age: number;
};
const obj: myType = {
  name: "aaa",
  age: 15,
};

interface myInterface {
  name: string;
  age: number;
}
const obj: myInterface = {
  name: "aaa",
  age: 15,
};

// 限制类结构
interface myInter {
  name: string;
  sayHello(): void;
}
// 实现接口
class MyClass implements myInter {
  name: string;

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

  sayHello(): void {
    console.log("Hello");
  }
}

(八)属性的封装

  • public 修饰的属性可以在任意位置访问(修改),默认值
  • private 私有属性,只能在当前类内部进行访问(修改)
    • 通过在类中添加方法使得私有属性可以被外部访问
    • getter 方法用来读取属性,setter 方法用来设置属性,统称为属性的存取器
  • protected 受保护属性,只能在当前类和其子类中进行访问(修改)
class Person {
  // 属性可以任意被修改,不安全
  // name: string;
  // age: number;
  private name: string;
  private age: number;

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

  // // 定义一个方法获取age属性
  // getAge() {
  //   return this.age;
  // }
  // // 定义一个方法修改age属性
  // setAge(val: string) {
  //   if (val >= 0) this.age = val;
  // }

  // TS中设置存取器
  get age() {
    return this.age;
  }
  set age(val: string) {
    if (val >= 0) this.age = val;
  }
}

const p = new Person("Alice", 20);
// p.name = "Tom";
// p.age = 30;
// console.log(p);

// getter & setter
// console.log(p.getAge());
// p.setAge(-33);

// TS get & set
console.log(p.age);
p.age = 30;
  • 可以直接将属性定义在构造函数中【语法糖】
class A {
  constructor(
    public name: string,
    private age: number,
  ) {}
}

const a = new A("Alice", 20);
console.log(a);
上次编辑于: