面试题-TS(4):如何在 TypeScript 中使用类和继承?
在TypeScript中,类是一种重要的概念,它允许我们使用面向对象的编程风格来组织和管理代码。类提供了一种模板,用于创建具有相同属性和行为的对象。通过继承,我们可以创建类之间的层次结构,实现代码的重用和扩展。
1. 类的定义和使用
在TypeScript中,我们使用class
关键字来定义类。以下是一个简单的类的示例:
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet(): void {
console.log(`Hello, my name is ${this.name}. I'm ${this.age} years old.`);
}
}
在上面的示例中,我们定义了一个名为Person
的类,它具有name
和age
属性,以及一个greet
方法。构造函数用于初始化对象的属性。
创建类的实例非常简单,只需使用new
关键字加上类的构造函数即可:
let person = new Person("John", 25);
person.greet(); // 输出:Hello, my name is John. I'm 25 years old.
通过类的定义,我们可以创建多个具有相同属性和行为的对象,实现代码的复用和封装。
2. 继承和子类
在面向对象编程中,继承是一种重要的概念。通过继承,我们可以创建一个类的子类(也称为派生类),并继承其属性和方法。子类可以扩展或修改父类的功能,从而实现代码的重用和扩展。
在TypeScript中,我们使用extends
关键字来指定一个类继承自另一个类。以下是一个简单的继承示例:
class Student extends Person {
studentId: string;
constructor(name: string, age: number, studentId: string) {
super(name, age);
this.studentId = studentId;
}
study(): void {
console.log(`Student ${this.name} is studying with student ID ${this.studentId}.`);
}
}
在上面的示例中,我们定义了一个名为Student
的子类,它继承自Person
父类。子类具有自己的属性studentId
,并通过调用super
关键字来调用父类的构造函数。
创建子类的实例与创建父类的实例类似:
let student = new Student("Alice", 20, "12345");
student.greet(); // 输出:Hello, my name is Alice. I'm 20 years old.
student.study(); // 输出:Student Alice is studying with student ID 12345.
通过继承和创建子类的实例,我们可以使用父类的属性和方法,并且可以扩展子类的功能。
3. 方法的重写
子类可以重写(override)父类的方法,以实现特定的行为。通过在子类中重新定义与父类相同名称的方法,可以覆盖父类中的方法实现。
以下是一个重写父类方法的示例:
class Teacher extends Person {
subject: string;
constructor(name: string, age: number, subject: string) {
super(name, age);
this.subject = subject;
}
greet(): void {
console.log(`Hello, my name is ${this.name}. I teach ${this.subject}.`);
}
}
在上面的示例中,我们定义了一个名为Teacher
的子类,它继承自Person
父类,并重写了父类的greet
方法。通过重写,我们可以在子类中定制特定的行为。
创建子类的实例并调用重写后的方法:
let teacher = new Teacher("Mr. Smith", 35, "Math");
teacher.greet(); // 输出:Hello, my name is Mr. Smith. I teach Math.
通过方法的重写,我们可以根据子类的需求来修改或扩展父类的行为。
4. 访问修饰符
在TypeScript中,我们可以使用访问修饰符来限制类的属性和方法的访问。以下是几个常用的访问修饰符:
public
(默认):可以在类内部和外部访问。private
:只能在类内部访问。protected
:可以在类内部和子类中访问,但不能在类外部访问。
例如
class Person {
public name: string;
private age: number;
protected gender: string;
constructor(name: string, age: number, gender: string) {
this.name = name;
this.age = age;
this.gender = gender;
}
sayHi() {
console.log(`Hi, my name is ${
this.name}.`);
}
private sayAge() {
console.log(`I am ${
this.age} years old.`);
}
}
class Student extends Person {
constructor(name: string, age: number, gender: string) {
super(name, age, gender);
}
sayGender() {
console.log(`My gender is ${
this.gender}.`);
}
}
let person = new Person("Tom", 18, "male");
console.log(person.name); // "Tom"
console.log(person.age); // Error: Property 'age' is private and only accessible within class 'Person'.
console.log(person.gender); // Error: Property 'gender' is protected and only accessible within class 'Person' and its subclasses.
let student = new Student("Jane", 20, "female");
console.log(student.gender); // "female"
通过使用访问修饰符,我们可以控制类的成员的可见性,增强了封装性和安全性。
5. 抽象类
在TypeScript中,我们还可以使用抽象类(abstract class)来定义一个不可实例化的基类。抽象类提供了一种模板,用于派生其他类,并定义了一些必须由子类实现的抽象方法。抽象类不能被直接实例化,只能被继承。
以下是一个抽象类的示例:
abstract class Shape {
abstract calculateArea(): number;
}
class Rectangle extends Shape {
width: number;
height: number;
constructor(width: number, height: number) {
super();
this.width = width;
this.height = height;
}
calculateArea(): number {
return this.width * this.height;
}
}
在上面的示例中,我们定义了一个抽象类Shape
,它具有一个抽象方法calculateArea
。子类Rectangle
继承自Shape
,并实现了calculateArea
方法。
通过抽象类,我们可以定义一些基础的行为和方法,并强制子类实现这些方法,从而实现了代码的规范和扩展性。
总结
使用类和继承可以使我们的代码更具结构和可读性,减少重复代码,并实现高度灵活和可扩展的应用程序。在TypeScript中充分利用类和继承的优势,将提升我们的开发效率和代码质量。