编程前端开发工程师

TypeScript中的访问修饰符(public,private,protected)是如何工作的?在继承和将代码转译为JavaScript时有什么注意事项?

用 Hintsage AI 助手通过面试

答案

在TypeScript中,访问修饰符用于限制类中属性和方法的可见性:

  • public — 属性或方法在任何地方可用(默认)。
  • private — 仅在声明它们的类中可用。
  • protected — 在类及其子类中可用。
class Animal { public name: string; private age: number; protected kind: string; constructor(name: string, age: number, kind: string) { this.name = name; this.age = age; this.kind = kind; } } class Dog extends Animal { bark() { console.log(this.kind); // OK: protected // console.log(this.age); // 错误: private在子类中不可见 } } const dog = new Dog('Sharik', 5, '哺乳动物'); console.log(dog.name); // OK // console.log(dog.kind); // 错误: protected // console.log(dog.age); // 错误: private

注意事项:

  • 在编译后的JavaScript中,privateprotected修饰符仅在编译阶段实现,运行时并没有物理隔离!JS代码将包含所有属性(例如,可以通过遍历对象获取它们)。
  • 在新版本中(从TypeScript 3.8开始)引入了真正私有字段的语法:#field,但这已经是JS的规范,并以不同的方式编译。

有陷阱的问题

问题: 在编译后,是否可以访问TypeScript类的private属性?

答案: 可以,因为private(和protected)是TypeScript在编译阶段的检查,编译为ES5或ES6后,私有性不再保持,属性仍然保留在对象中,并且可以通过属性名称访问(例如,通过object['privateProp'])。

// 编译后的JS代码 function Animal(name, age, kind) { this.name = name; this.age = age; this.kind = kind; } var dog = new Animal('Sharik', 5, '哺乳动物'); console.log(dog['age']); // 5 — 只有在TS级别没有访问权限!

因为不了解此主题的细微差别而产生的实际错误示例。


故事

在一个大型项目中,开发人员期望private字段在运行时不可用。因此,在通过序列化(JSON.stringify)传递对象时,机密数据意外地进入日志,因为TS类型检查没有保护对字段的实际访问。


故事

在一个项目中实现了通过动态添加属性“扩展”类实例的机制。动态添加的属性覆盖了private名称,外部代码意外地修改了它们。错误仅在生产环境中被发现,并且私有性没有得到保障。


故事

在从JavaScript迁移到TypeScript时,团队开始使用protected,认为这可以防止在子类外部使用字段。但程序员通过Object.assign错误地在运行时覆盖了protected字段,并导致了难以调试的错误。这是可能的,因为运行时没有封装。