TS和JS成员变量修饰符

在 TypeScript 和 JavaScript 中,类成员变量(属性)的修饰符(Modifiers) 用于控制其可见性、可访问性和可变性 。两者在能力上有显著差异:TypeScript 提供了更丰富的编译时修饰符 ,而 JavaScript(ES2022 起)引入了运行时私有字段

下面从 TypeScriptJavaScript 两个角度分别说明,并对比异同。


一、TypeScript 类成员变量修饰符(编译时)

TypeScript 在 编译阶段 提供以下关键字作为访问修饰符:

修饰符 含义 是否生成 JS 代码 可见性
public 公共(默认) ❌ 不生成额外代码 类内、子类、外部均可访问
private 私有 ❌ 仅类型检查,不阻止运行时访问 仅类内部可访问(TS 编译时报错)
protected 受保护 ❌ 仅类型检查 类内部 + 子类可访问
readonly 只读 ❌ 仅类型检查 初始化后不可修改(TS 报错)

✅ 示例(TypeScript):

typescript 复制代码
class User {
  public name: string;        // 默认就是 public
  private id: number;         // TS 禁止外部访问
  protected email: string;    // 子类可访问
  readonly createdAt: Date;   // 初始化后不可改

  constructor(name: string, id: number, email: string) {
    this.name = name;
    this.id = id;
    this.email = email;
    this.createdAt = new Date();
  }
}

⚠️ 注意:
private / protected 只在 TypeScript 编译时生效 ,编译成 JS 后,这些字段仍是普通属性,运行时仍可被访问或修改

ini 复制代码
// 编译后的 JS(无 private 保护!)
const user = new User("Alice", 1, "a@example.com");
console.log(user.id); // ✅ 能访问!JS 不报错
user.id = 999;        // ✅ 能修改!

二、JavaScript 类成员变量修饰符(运行时,ES2022+)

ECMAScript 2022(ES13) 开始,JavaScript 原生支持 真正的私有字段(Private Fields) ,使用 # 前缀。

语法 含义 运行时是否私有 是否可被外部访问
#fieldName 私有字段 ✅ 是 ❌ 完全无法从类外访问
普通字段(无前缀) 公共字段 ❌ 否 ✅ 可自由访问

✅ 示例(JavaScript / TypeScript 均支持):

arduino 复制代码
class User {
  #id;                    // 私有字段(JS 原生私有)
  name;                   // 公共字段

  constructor(name, id) {
    this.name = name;
    this.#id = id;        // 只能在类内部访问
  }

  getId() {
    return this.#id;      // ✅ OK
  }
}

const user = new User("Bob", 2);
console.log(user.name);   // ✅ "Bob"
console.log(user.#id);    // ❌ SyntaxError! 无法访问

关键优势
#id真正的私有,即使在运行时也无法绕过(除非用 Proxy 等 hack,但正常代码做不到)。


三、TypeScript 对 JS 私有字段的支持

TypeScript 完全支持 # 私有字段,并提供类型检查:

typescript 复制代码
class User {
  #id: number;
  name: string;

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

  getId(): number {
    return this.#id; // ✅ TS 知道这是 number
  }
}

🔸 此时你不需要private,因为 #id 已经是运行时私有。


四、对比总结

特性 TypeScript private JavaScript #field
作用时机 编译时(类型检查) 运行时(真实私有)
能否被外部访问 ✅ 能(JS 无保护) ❌ 不能
是否生成额外代码 ❌ 否 ✅ 是(保留 # 语法)
兼容性 所有 JS 环境(因被擦除) 需要 ES2022+ 或 Babel 转译
推荐场景 快速开发、内部项目 需要真正封装、库开发

五、最佳实践建议

✅ 优先使用 JavaScript 原生私有字段 #

  • 如果目标环境支持(现代浏览器 / Node.js 12+),优先用 #fieldName
  • 它提供真正的封装,避免"假装私有"的陷阱。

✅ 在 TypeScript 中:

  • 若需兼容旧环境 → 用 private(但要清楚它只是"纸面私有")。
  • 若用现代环境 → 直接用 # ,无需 private

✅ 不要混用:

arduino 复制代码
// ❌ 不推荐:语义重复且混乱
private #id; // 错误!不能同时用

readonly 仍是 TS 特有(JS 无等价物)

  • 可配合 # 使用:

    typescript 复制代码
    class Config {
      readonly #apiUrl: string;
      constructor(url: string) {
        this.#apiUrl = url; // 初始化后不可变(TS 检查)
      }
    }

六、补充:其他相关修饰符

修饰符 语言 说明
static TS & JS 静态成员(属于类,不属于实例)
abstract TS only 抽象类/方法(不能实例化)
declare TS only 声明属性存在(用于 .d.ts 或装饰器)

✅ 总结

需求 推荐方案
真正的私有字段 使用 JavaScript #fieldName(ES2022+)
仅开发时提醒(兼容旧环境) 使用 TypeScript private
只读属性 TypeScript readonly(JS 无原生支持)
公共字段 直接声明(TS/JS 均默认 public)

🎯 现代项目建议
# 实现私有,用 readonly 实现只读,放弃 private(除非必须兼容旧 JS)

这样既能获得类型安全,又能保证运行时封装性。

相关推荐
我叫张小白。1 小时前
Vue3 响应式数据:让数据拥有“生命力“
前端·javascript·vue.js·vue3
laocooon5238578861 小时前
vue3 本文实现了一个Vue3折叠面板组件
开发语言·前端·javascript
科普瑞传感仪器2 小时前
从轴孔装配到屏幕贴合:六维力感知的机器人柔性对位应用详解
前端·javascript·数据库·人工智能·机器人·自动化·无人机
n***F8752 小时前
SpringMVC 请求参数接收
前端·javascript·算法
TechMasterPlus2 小时前
VScode如何调试javascript文件
javascript·ide·vscode
牧码岛3 小时前
Web前端之canvas实现图片融合与清晰度介绍、合并
前端·javascript·css·html·web·canvas·web前端
灵犀坠3 小时前
前端面试八股复习心得
开发语言·前端·javascript
网络点点滴3 小时前
Vue3嵌套路由
前端·javascript·vue.js
牧码岛3 小时前
Web前端之Vue+Element打印时输入值没有及时更新dom的问题
前端·javascript·html·web·web前端