19.类与访问修饰符 副本.md 来源:https://my.feishu.cn/file/B3QzbKFoUoPFK9x0nlCceK3mnbe 采集状态:已完成正文采集;已从查看代码模式逐行提取,行号 1 至 180 连续,并核对滚动到底。 在 JavaScript ES6 之前,开发者们通过原型链(prototypal inheritance)来模拟面向对象的编程范式。虽然功能强大,但其语法和心智模型对于有传统面向对象语言(如 Java 或 C#)背景的开发者来说,常常显得不够直观。ES6 引入了 `class` 关键字,提供了一套更清晰、更熟悉的语法糖。而 TypeScript 则在此基础上,更进一步,引入了完整的类型支持和强大的访问控制机制,将 JavaScript 的面向对象能力提升到了一个全新的工程化高度。 本文将深入探讨 TypeScript 中类的定义,并重点解析其访问控制的核心——`public`、`private` 和 `protected` 修饰符。 ### 类的基本解剖:蓝图的构建 在面向对象编程中,**类 (Class)** 是创建对象的**蓝图 (Blueprint)**。它定义了一类事物所共有的**属性 (Properties)**(状态)和**方法 (Methods)**(行为)。 让我们通过构建一个简单的 `Player` 类来理解其基本结构: ```typescript class Player { // 1. 属性 (Properties) username: string; health: number; isOnline: boolean; // 2. 构造函数 (Constructor) constructor(username: string) { this.username = username; this.health = 100; // 初始生命值为 100 this.isOnline = true; console.log(`Welcome, ${this.username}!`); } // 3. 方法 (Methods) attack(target: Player): void { if (!this.isOnline || !target.isOnline) { console.log("One of the players is offline."); return; } console.log(`${this.username} attacks ${target.username}!`); // ... 复杂的伤害计算逻辑 } disconnect(): void { this.isOnline = false; console.log(`${this.username} has disconnected.`); } } ``` 这个 `Player` 类包含了构成一个类的三个核心部分: 1. **属性**:我们在类的主体中声明了 `username`, `health`, `isOnline` 等属性,并为它们指定了类型。这些属性构成了每个 `Player` 实例的内部状态。 2. **构造函数**:`constructor` 是一个特殊的方法,它在通过 `new` 关键字创建类的新实例时被自动调用。它的主要职责是初始化对象的属性。 3. **方法**:`attack` 和 `disconnect` 是定义在类上的函数,它们描述了 `Player` 对象能够执行的行为。方法可以访问和修改实例的属性(通过 `this` 关键字)。 创建和使用类的实例(即对象)非常直观: ```typescript const player1 = new Player("Alice"); const player2 = new Player("Bob"); player1.attack(player2); // 输出: Alice attacks Bob! player2.disconnect(); // 输出: Bob has disconnected. ``` ### 访问修饰符:封装的艺术 仅仅定义结构是不够的。一个健壮的系统还需要**封装 (Encapsulation)**——即隐藏对象的内部实现细节,只暴露必要的接口供外部使用。这可以防止外部代码随意篡改对象的状态,从而保证系统的稳定性和可维护性。 TypeScript 为此提供了三个访问修饰符:`public`、`private` 和 `protected`。 #### 1. `public` (公开的) `public` 是最宽松的访问级别,也是**默认的**修饰符。如果你不显式指定任何修饰符,那么该成员就是 `public` 的。被标记为 `public` 的属性或方法可以在任何地方被访问——包括类的内部、类的实例外部,以及子类中。 ```typescript class Greeter { public message: string; // 显式标记为 public constructor(message: string) { this.message = message; } } const greeter = new Greeter("Hello"); console.log(greeter.message); // 可以在外部访问 ``` #### 2. `private` (私有的) `private` 是最严格的访问级别。被标记为 `private` 的成员**只能在定义它的那个类的内部**被访问。类的实例外部和子类都无法访问。这对于隐藏那些不应被外部知晓的内部状态或辅助方法至关重要。 ```typescript class BankAccount { private balance: number = 0; constructor(initialBalance: number) { if (this.isValidAmount(initialBalance)) { this.balance = initialBalance; } } public deposit(amount: number): void { if (this.isValidAmount(amount)) { this.balance += amount; console.log(`Deposited ${amount}. New balance: ${this.balance}`); } } // 这是一个私有的辅助方法,外部无需关心其实现 private isValidAmount(amount: number): boolean { return amount > 0; } } const account = new BankAccount(100); account.deposit(50); // console.log(account.balance); // 编译时错误: Property 'balance' is private and only accessible within class 'BankAccount'. // account.isValidAmount(10); // 编译时错误: Property 'isValidAmount' is private... ``` #### 3. `protected` (受保护的) `protected` 是介于 `public` 和 `private` 之间的一种访问级别。被标记为 `protected` 的成员可以在**定义它的类的内部**以及**该类的子类中**被访问。但是,它不能在类的实例外部被访问。 这对于创建可被子类扩展和定制的基类非常有用。 ```typescript class Animal { protected name: string; constructor(name: string) { this.name = name; } } class Dog extends Animal { public bark(): void { // 可以在子类中访问受保护的成员 console.log(`Woof! My name is ${this.name}.`); } } const dog = new Dog("Buddy"); dog.bark(); // 输出: Woof! My name is Buddy. // console.log(dog.name); // 编译时错误: Property 'name' is protected and only accessible within class 'Animal' and its subclasses. ``` ### 实践捷径:参数属性 TypeScript 提供了一种非常便利的语法糖,叫做**参数属性 (Parameter Properties)**。它允许我们在构造函数的参数上直接使用访问修饰符,从而将参数的声明、赋值和属性的定义合并为一步。 **传统方式:** ```typescript class Person { public name: string; public age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } } ``` **使用参数属性的简洁方式:** ```typescript class Person { constructor(public name: string, public age: number) { // 构造函数体可以是空的,因为声明和赋值已经自动完成 } } ``` 这两种写法在功能上是完全等价的,但第二种显然更加简洁高效,是 TypeScript 开发中的常用技巧。 ### 总结 类是 TypeScript 实现结构化和面向对象编程的核心。它通过将数据(属性)和行为(方法)封装在一起,为我们提供了构建复杂系统的坚实基础。 * **类**是创建对象的蓝图,包含**属性**、**构造函数**和**方法**。 * **访问修饰符**是实现封装的关键: * `public`:无限制访问(默认)。 * `private`:仅限类内部访问。 * `protected`:类内部及其子类可以访问。 * **参数属性**是简化类定义的实用语法糖。 通过熟练运用类及其访问控制机制,我们可以编写出更模块化、更安全、更易于维护和扩展的高质量代码。