在JavaScript中class(类)是一种组织代码的方式,它允许我们创建对象和对象的行为。它是一种面向对象编程(OOP)的概念,在ES6中被引入,通过class关键字,可以定义类。使用class关键字可以定义类,通过类可以创建多个实例对象。本章将讲解如何在TypeScript 中使用class(类)。
定义类的语法与JavaScript类似,使用
class
关键字来定义一个类。类可以包含属性、方法和构造函数等。
注意:在TypeScript是不允许直接在constructor 定义变量的 需要先在constructor的上面进行声明
例如,下面是一个简单的示例,演示了如何在TypeScript中定义一个类:
class Person {
//先进行声明
name: string;
age: number;
//才能在constructor 中使用
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
}
}
let person = new Person("John", 25);
person.sayHello();
在上面的例子中,我们定义了一个名为Person
的类,它有两个属性name
和age
,一个构造函数和一个sayHello
方法。构造函数用于创建类的实例,并接受name
和age
作为参数。
我们可以使用new
关键字来创建一个Person
对象,并调用sayHello
方法来输出欢迎消息。
类成员(属性和方法)可以使用以下修饰符来定义其访问权限:
例如,以下代码示例演示了如何使用修饰符:
class Person {
public name: string; // 公有属性,默认修饰符
private age: number; // 私有属性
protected gender: string; // 受保护属性
readonly id: string; // 只读属性
static count: number; // 静态属性
constructor(name: string, age: number, gender: string, id: string) {
this.name = name;
this.age = age;
this.gender = gender;
this.id = id;
Person.count++;
}
public sayHello() {
console.log(`Hello, my name is ${this.name}.`);
}
private getAge() {
return this.age;
}
protected getGender() {
return this.gender;
}
static getCount() {
return Person.count;
}
}
const person = new Person('John', 25, 'male', '1234567890');
console.log(person.name); // 可访问,输出 'John'
// console.log(person.age); // 私有属性,无法访问
// console.log(person.gender); // 受保护属性,无法访问
console.log(person.id); // 只读属性,可访问,输出 '1234567890'
person.sayHello(); // 可调用,输出 'Hello, my name is John.'
// person.getAge(); // 私有方法,无法调用
// person.getGender(); // 受保护方法,无法调用
console.log(Person.count); // 静态属性,可直接访问,输出当前实例数
这是一个使用各种修饰符定义类成员的例子,你可以根据自己的需求选择适当的修饰符来限制成员的访问权限。
存取器(accessor)是一种特殊的属性,用于对类的属性进行读取和写入操作。存取器由get和set关键字定义,分别用于获取和设置属性的值。
下面是一个使用存取器的示例:
class Person {
private _name: string;
get name(): string {
return this._name;
}
set name(value: string) {
this._name = value;
}
}
let person = new Person();
person.name = "Alice";
console.log(person.name); // Output: Alice
在上面的例子中,Person
类具有一个私有属性_name
和一个公共的存取器name
。存取器name
的get方法返回_name
的值,set方法设置_name
的值。通过使用存取器,我们可以在外部像访问属性一样获取和设置_name
的值。
另外,存取器可以有只读的属性。只读属性只有get方法,没有set方法,一旦设置了初始值后就不能再修改。
class Person {
private readonly _name: string;
constructor(name: string) {
this._name = name;
}
get name(): string {
return this._name;
}
}
let person = new Person("Alice");
console.log(person.name); // Output: Alice
person.name = "Bob"; // Error: Cannot assign to 'name' because it is a read-only property
在上面的例子中,Person
类的_name
属性是只读的,只能通过构造函数初始化,并且不能修改其值。通过使用只读属性,我们可以限制属性的修改,提高代码的可靠性和安全性。
可以使用接口来定义类。可以在接口中定义类的属性和方法,并且类需要遵循接口的定义。
下面是一个示例:
interface Animal {
name: string;
age: number;
sound(): void;
}
class Dog implements Animal {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sound(): void {
console.log("Woof!");
}
}
let myDog: Animal = new Dog("Max", 5);
myDog.sound(); // 输出 "Woof!"
在上面的例子中,定义了一个Animal接口,它包含了name、age和sound方法。然后创建了一个Dog类,它实现了Animal接口。最后,创建了一个myDog对象,它是一个Animal类型的变量,可以调用sound方法。
通过使用接口来定义类,可以使代码更加清晰和易于维护,同时也可以提供更好的类型检查和类型推断。
类之间可以通过继承来建立父子关系。一个类可以继承另一个类的属性和方法,并且可以添加自己的属性和方法。类的继承使用
extends
关键字。
下面是一个示例,展示了一个父类 Animal
和一个子类 Cat
的继承关系:
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
makeSound() {
console.log('Animal is making a sound.');
}
}
class Cat extends Animal {
meow() {
console.log('Cat is meowing.');
}
}
const myCat = new Cat('Tom');
console.log(myCat.name); // 输出 "Tom"
myCat.makeSound(); // 输出 "Animal is making a sound."
myCat.meow(); // 输出 "Cat is meowing."
在上面的例子中,Cat
类继承了 Animal
类,因此它拥有了 name
属性和 makeSound()
方法。同时,它还添加了自己的方法 meow()
。
注意,当子类继承父类时,子类的构造函数中必须调用 super()
方法,以调用父类的构造函数,并传递必要的参数。在上面的例子中,Cat
类的构造函数调用了 super(name)
,以调用 Animal
类的构造函数。
此外,子类还可以重写父类的方法。在子类中,可以使用 super
关键字来调用父类的方法。例如,在上面的例子中,Cat
类的 makeSound()
方法重写了父类的方法,但在方法体内部通过 super.makeSound()
来调用父类的方法。
可以使用抽象类来定义一个抽象的基类,它不能被直接实例化,只能被继承。抽象类可以包含抽象方法和非抽象方法。
下面是一个使用抽象类的示例:
abstract class Animal {
protected name: string;
constructor(name: string) {
this.name = name;
}
abstract makeSound(): void;
move(distance: number): void {
console.log(`${this.name} moved ${distance} meters.`);
}
}
class Cat extends Animal {
makeSound(): void {
console.log(`${this.name} makes sound: Meow!`);
}
}
let myCat: Cat = new Cat("Tom");
myCat.makeSound(); // 输出 "Tom makes sound: Meow!"
myCat.move(10); // 输出 "Tom moved 10 meters."
在上述代码中,Animal
类是一个抽象类,它有一个抽象方法 makeSound
和一个非抽象方法 move
。Cat
类继承自 Animal
类,并实现了 makeSound
方法。我们创建一个 Cat
类的实例 myCat
,并调用它的方法和非抽象方法。
总结起来,使用 TypeScript类可以方便地定义和组织代码,提供了面向对象编程的特性,如封装、继承和多态。同时,通过类型检查,可以减少一些常见的错误,并提供更好的代码智能提示。