Get to know MDN better
此页面由社区从英文翻译而来。了解更多并加入 MDN Web Docs 社区。
私有元素是常规的类的公有属性(包括类字段、类方法等)的对应。私有元素通过添加 # 前缀来创建,在类的外部无法合法地引用。这些类属性的私有封装由 JavaScript 本身强制执行。
在这种语法出现之前,JavaScript 语言本身并没有原生支持私有元素。在原型继承中,可以通过使用 WeakMap 对象或者闭包的方式来模拟私有元素的行为,但就易用性而言,它们无法与 # 语法相提并论。
还有一些额外的语法限制:
大多数类元素都有其对应的私有项:
这些特性统称为私有元素。然而,JavaScript 中构造函数不能是私有的。为了防止在类之外构造类,你必须使用私有标志。
私有元素通过“#名称”(“#”读作“hash”)来声明,它们是以 # 前缀开头的标识符。这个 # 前缀是属性名称的固有部分,你可以将其与旧的下划线前缀约定 _privateField 进行类比,但它不是普通的字符串属性,因此无法使用方括号表示法动态访问它。
在类外部引用 # 名称、引用未在类内部声明的私有元素,或尝试使用 delete 移除声明的元素都会抛出语法错误。
JavaScript 作为动态语言,能够在编译时检查 # 标识符的语法,使其与普通属性的语法不同。
备注:Chrome 控制台中运行的代码可以访问类的私有元素。这是 JavaScript 语法限制对开发者工具的一种放宽。
如果你访问对象中不存在的私有元素,会抛出 TypeError 错误,而不是像普通属性一样返回 undefined。
这个示例也演示了你可以在静态函数中以及在外部定义的类的实例上访问私有元素。
你也可以使用 in 运算符来检查一个外部定义的对象是否拥有一个私有元素。如果对应的私有字段或私有方法存在,则返回 true,否则返回 false。
请注意,私有名称始终需要提前声明并且不可删除:如果你发现一个对象具有当前类的一个私有元素(无论是通过 try...catch 还是 in 检查),那么它一定具有其他所有的私有元素。通常情况下,一个对象具有一个类的私有元素意味着它是由该类构造的(尽管并非总是如此)。
私有元素不是原型继承模型的一部分,因为它们只能在当前类内部被访问,而且不能被子类继承。不同类的私有元素名称之间没有任何交互。它们是附加在每个实例上的外部元数据,由类本身管理。因此,Object.freeze() 和 Object.seal() 对私有元素没有影响。
关于如何以及何时初始化私有字段的更多信息,请参阅公有类字段。
私有字段包括私有实例字段和私有静态字段。私有字段只能在类声明内部被访问。
类似于对应的公有字段,私有实例字段:
备注:ClassWithPrivateField 基类的 #privateField 是 ClassWithPrivateField 私有的,不能从派生的 Subclass 类中访问。
类的构造函数可以返回一个不同的对象,这个对象将被用作派生类的构造函数的 this。派生类可以在这个返回的对象上定义私有字段——这意味着可以将私有字段“附加”到不相关的对象上。
警告:这可能是一种非常令人困惑的做法。你应该避免从构造函数返回任何东西——尤其是与 this 无关的东西。
类似于公有静态字段,私有静态字段:
私有静态字段有一些限制:只有定义私有静态字段的类才能访问该字段。这可能导致使用 this 时出现意想不到的行为。在下面的例子中,this 指向 Subclass 类(而不是 ClassWithPrivateStaticField 类),导致尝试调用 Subclass.publicStaticMethod() 时抛出 TypeError。
如果你使用 super 来调用该方法,也是如此,因为 super 方法被调用时不会将基类作为 this 值。
建议你始终通过类名来访问私有静态字段,而不是通过 this,以避免继承破坏方法。
私有方法包括私有实例方法和私有静态方法。私有方法只能在类声明内部被访问。
与公有实例方法不同,私有实例方法:
私有实例方法可以是生成器方法、异步方法或异步生成器方法。私有 getter 和 setter 方法也同样适用,并且与公有 getter 和 setter 方法的语法相同。
与公有方法不同,私有方法不能在类的 .prototype 属性上访问。
与公有静态方法类似,私有静态方法:
私有静态方法可以是生成器方法,异步方法或异步生成器方法。
前面提到的私有静态字段的限制同样适用于私有静态方法。同样地,使用 this 可能会出现意想不到的行为。在下面的例子中,当我们尝试调用 Subclass.publicStaticMethod() 时,this 指向 Subclass 类(而不是 ClassWithPrivateStaticMethod 类),导致抛出 TypeError。
许多其他语言都提供了将构造函数标记为私有的能力,这将阻止类在类内部外被实例化——只能使用创建实例的静态工厂方法,或者根本不能创建实例。JavaScript 没有原生的私有构造函数的语法,但可以通过私有静态标志来实现。
| ECMAScript® 2027 Language Specification # prod-PrivateIdentifier |
| ECMAScript® 2027 Language Specification # prod-00OK517S |
启用 JavaScript 以查看此浏览器兼容性表。
启用 JavaScript 以查看此浏览器兼容性表。
启用 JavaScript 以查看此浏览器兼容性表。