详解JavaScript私有类字段和TypeScript私有修饰符

作者:函数茶馆

时间:2026-10-24

浏览:628

本文深入解析JavaScript原生私有类字段与TypeScript中private修饰符的本质区别。指出TypeScript的private仅编译时检查,编译后字段仍为公有;而JS原生私有字段(#前缀)通过WeakMap实现运行时真正隔离,但需ES2015+目标及polyfill支持,存在浏览器兼容性与开发成本权衡。

文章目录

JavaScript私有类字段和隐私需求

在早期JavaScript中,缺乏保护变量不被外部直接访问的原生机制,除非利用闭包特性。

闭包构成了JavaScript中多种类似私有模式的基石,例如广受欢迎的模块模式。然而,随着ECMAScript 2015引入类语法,开发者对类成员访问权限的控制需求日益增强。

类字段提案(截至文章撰写时处于第3阶段)旨在通过引入私有类字段来解决这一痛点。

下面展示其具体形态。

一个JavaScript私有类字段的例子

以下是一个包含私有字段的JavaScript类示例。需注意,与公有成员不同,每个私有字段在使用前必须先进行声明。


class Person {
  #age;
  #name;
  #surname;
  constructor(name, surname, age) {
    this.#name = name;
    this.#surname = surname;
    this.#age = age;
  }
  getFullName() {
    return `${this.#name} + ${this.#surname}`;
  }
}

私有类字段无法从类外部直接访问:


class Person {
  #age;
  #name;
  #surname;
  constructor(name, surname, age) {
    this.#name = name;
    this.#surname = surname;
    this.#age = age;
  }
  getFullName() {
    return `${this.#name} + ${this.#surname}`;
  }
}
const marta = new Person("Marta", "Cantrell", 33);
console.log(marta.#age); // SyntaxError

这实现了真正的“隐私”。若熟悉TypeScript,读者可能会疑惑:这种“原生”私有字段与TypeScript中的private修饰符有何异同。

答案是没有共同点。原因何在?

TypeScript中的private修饰符

拥有传统编程语言经验的开发者对TypeScript中的private关键字并不陌生。简言之,该关键字旨在阻止从类外部访问类成员。

但需注意,TypeScript是运行在JavaScript之上的类型层,TypeScript编译器会剥离所有TypeScript特有的注释,包括private关键字。

这意味着以下代码无法实现预期的私有效果:


class Person {
  private age: number;
  private name: string;
  private surname: string;
  constructor(name: string, surname: string, age: number) {
    this.name = name;
    this.surname = surname;
    this.age = age;
  }
  getFullName() {
    return `${this.name} + ${this.surname}`;
  }
}
const liz = new Person("Liz", "Cantrill", 31);
// @ts-ignore
console.log(liz.age);

若不使用//@ts-ignore,在TypeScript环境中访问liz.age时会报错;但编译生成的JavaScript代码中,该字段依然可被访问:


"use strict";
var Person = /** @class */ (function () {
    function Person(name, surname, age) {
        this.name = name;
        this.surname = surname;
        this.age = age;
    }
    Person.prototype.getFullName = function () {
        return this.name + " + " + this.surname;
    };
    return Person;
}());
var liz = new Person("Liz", "Cantrill", 31);
console.log(liz.age); // 31

如预期所示,我们可以从控制台输出liz.age。核心观点在于:TypeScript中的private并非真正的私有,它仅在TypeScript编译阶段提供便利,而非运行时隐私。

接下来讨论:TypeScript中支持的“原生”私有类字段。

TypeScript中的私有类字段

TypeScript 3.8开始支持ECMAScript私有字段,切勿将其与TypeScript的private修饰符混淆。

这是在TypeScript中使用私有类字段的类示例:


class Person {
    #age: number;
    #name: string;
    #surname: string;
    constructor(name:string, surname:string, age:number) {
        this.#name = name;
        this.#surname = surname;
        this.#age = age;
    }
    getFullName() {
        return `${this.#name} + ${this.#surname}`;
    }
}

除类型注释外,这与原生JavaScript无异,成员无法从外部访问。然而,TypeScript中私有字段的真正问题在于其底层实现依赖于WeakMap。

为编译此代码,需调整tsconfig.json中的目标编译版本,最低要求为ECMAScript 2015:


{
  "compilerOptions": {
    "target": "es2015",
    "strict": true,
    "lib": ["dom","es2015"]
  }
}

这可能导致兼容性问题。具体取决于目标浏览器,若需为WeakMap提供polyfill,则仅为使用新语法而增加的工作量可能得不偿失。

JavaScript中始终存在这种张力:既希望使用新语法,又不愿因大量polyfill影响用户体验。

另一方面,即使计划发布至较新浏览器,也无需过度担忧私有类字段。至少目前如此,甚至Firefox尚未完全实施该提案。

以上就是详解JavaScript私有类字段和TypeScript私有修饰符的详细内容,更多关于JavaScript私有类字段和TypeScript私有修饰符的资料请关注本站其它相关文章!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章