现在位置: 首页 > TypeScript 教程 > 正文

TypeScript 访问修饰符

访问修饰符(Access Modifiers)是 TypeScript 面向对象编程的核心特性之一。

它们用于控制类成员(属性、方法、构造函数)的可见性。

通过访问修饰符,可以实现封装,保护类的内部实现细节。


访问修饰符作用域 public 类内部 ✓ 子类 ✓ 外部 ✓ protected 类内部 ✓ 子类 ✓ 外部 ✗ private 类内部 ✓ 子类 ✗ 外部 ✗ 使用场景 public 公开方法/属性 如:用户姓名、登录方法 protected 子类可见方法 如:计算公式、模板方法 private 内部实现细节 如:数据库连接、内部计算

为什么需要访问修饰符

面向对象编程的三大原则之一是封装。

封装意味着将数据和操作数据的方法隐藏起来,对外只暴露必要的接口。

访问修饰符就是实现封装的手段,它控制类成员的可见范围。

概念说明:访问修饰符决定了类成员可以在哪里被访问。TypeScript 提供三种访问修饰符:public、protected、private。


public 修饰符

public 是默认的访问修饰符,表示成员可以在任何地方被访问。

无论是类内部、子类还是类的外部,都可以访问 public 成员。

实例

// 定义动物类
class Animal {
    // 使用 public 修饰 name 属性(可以省略,默认就是 public)
    public name: string;

    // 构造函数
    public constructor(name: string) {
        this.name = name;
    }

    // 公开的说话方法
    public speak(): void {
        console.log(this.name + " 发出声音");
    }
}

// 创建实例
var animal = new Animal("动物");

// 在类外部访问 public 属性
console.log(animal.name);

// 在类外部调用 public 方法
animal.speak();

运行结果:

动物
动物 发出声音

说明:如果不写访问修饰符,TypeScript 会默认使用 public。因此 public 可以省略,但为了代码清晰,建议明确声明。


private 修饰符

private 表示私有成员,只能在定义它的类内部访问。

子类和类的外部都不能访问 private 成员。

这常用于隐藏类的内部实现细节,保护数据不被意外修改。

实例

// 定义银行账户类
class BankAccount {
    // 使用 private 修饰余额,只能在类内部访问
    private balance: number;

    // 构造函数
    constructor(initialBalance: number) {
        this.balance = initialBalance;
    }

    // 存款方法
    public deposit(amount: number): void {
        if (amount > 0) {
            this.balance += amount;  // 类内部可以访问 private 属性
            console.log("存款成功,当前余额: " + this.balance);
        }
    }

    // 获取余额
    public getBalance(): number {
        return this.balance;  // 类内部可以访问 private 属性
    }
}

// 创建账户实例
var account = new BankAccount(1000);

// 存款
account.deposit(500);

// 通过公共方法获取余额
console.log("余额: " + account.getBalance());

// 错误:在类外部不能直接访问 private 属性
// console.log(account.balance); // 编译错误!

运行结果:

存款成功,当前余额: 1500
余额: 1500

最佳实践:将类的内部状态设为 private,通过 public 方法提供受控的访问途径,这是实现封装的标准做法。


protected 修饰符

protected 表示受保护成员,可以在类内部和子类中访问。

类的外部不能直接访问 protected 成员。

这在需要让子类继承父类的某些功能,同时隐藏实现细节时非常有用。

实例

// 定义人员基类
class Person {
    // 使用 protected 修饰 name,子类可以访问
    protected name: string;

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

// 定义员工类,继承 Person
class Employee extends Person {
    // 部门是私有的
    private department: string;

    constructor(name: string, department: string) {
        super(name);  // 调用父类构造函数
        this.department = department;
    }

    // 自我介绍方法
    public introduce(): string {
        // 子类可以访问 protected 成员 name
        return "我是 " + this.name + ",在 " + this.department + " 工作";
    }
}

// 创建员工实例
var emp = new Employee("Alice", "技术部");

console.log(emp.introduce());

// 错误:在类外部不能访问 protected 成员
// console.log(emp.name); // 编译错误!

运行结果:

我是 Alice,在 技术部 工作

应用场景:protected 常用于定义子类需要使用的属性,但不应该暴露给外部的值。


readonly 修饰符

readonly 用于将属性设置为只读。

只能在声明时或构造函数中赋值,之后不能修改。

这在定义常量或标识符时非常有用。

实例

// 定义用户类
class User {
    // 使用 readonly 修饰的属性只能在初始化时赋值
    // 用户 ID
    readonly id: number;
    // 用户名
    readonly name: string;

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

// 创建用户实例
var user = new User(1, "Alice");

console.log("用户: " + user.id + ", " + user.name);

// 错误:不能修改 readonly 属性
// user.id = 2; // 编译错误!
// user.name = "Bob"; // 编译错误!

运行结果:

用户: 1, Alice

注意:readonly 和 private 不冲突。可以同时使用 readonly 和 private,既不能修改也不能从外部访问。


参数属性

TypeScript 提供了参数属性(Parameter Properties)的简写语法。

可以在构造函数的参数上直接使用访问修饰符,自动创建并初始化属性。

实例

// 定义点类
class Point {
    // 在构造函数参数上直接使用修饰符
    // 相当于同时声明属性并赋值
    constructor(
        // public 修饰:创建公开属性 x
        public x: number,
        // public 修饰:创建公开属性 y
        public y: number,
        // private 修饰:创建私有属性 z
        private z: number
    ) {
        // 构造函数体可以为空,属性已自动创建
    }

    // 计算三维度总和
    public sum(): number {
        // 可以在类内部访问所有属性
        return this.x + this.y + this.z;
    }
}

// 创建点实例
var point = new Point(1, 2, 3);

// 公开属性可以从外部访问
console.log("x: " + point.x);
console.log("y: " + point.y);

// 调用方法
console.log("总和: " + point.sum());

// 错误:私有属性不能从外部访问
// console.log(point.z); // 编译错误!

运行结果:

x: 1
y: 2
总和: 6

简化代码:参数属性可以大幅简化类的定义,避免重复的声明和赋值代码。


访问修饰符对比

下面是三种访问修饰符的作用范围对比。

修饰符 类内部 子类 类外部(实例)
public ✓ 可以访问 ✓ 可以访问 ✓ 可以访问
protected ✓ 可以访问 ✓ 可以访问 ✗ 不能访问
private ✓ 可以访问 ✗ 不能访问 ✗ 不能访问

选择建议:默认情况下使用 private,需要子类访问时使用 protected,需要完全公开时使用 public。


注意事项

  • 默认修饰符:不写修饰符时默认为 public
  • 构造函数:构造函数也可以使用访问修饰符,控制实例化权限
  • readonly 组合:readonly 可以与 public、protected、private 组合使用
  • 编译影响:访问修饰符仅在编译时检查,运行时无效

最佳实践:尽可能使用最严格的访问修饰符。只暴露必要的公开接口,将内部实现设为 private 或 protected。


总结

访问修饰符是 TypeScript 实现封装的核心工具。

  • public:公开访问,是默认值
  • private:私有,仅类内部可见
  • protected:保护,类内部和子类可见
  • readonly:只读,初始化后不可修改
  • 参数属性:简化属性声明的语法

建议:养成使用访问修饰符的习惯,这是编写高质量 TypeScript 代码的基础。