Non-extensible Applies to Private S3
中文标题:不可扩展性适用于私有字段
- 阶段: Stage 3
- 状态: 进行中
- ECMAScript 版本: —
- 同步时间: 2026年8月26日
- English original · 官方仓库
该提案将不可扩展性修改为也禁止向不可扩展对象添加私有字段,与现有公共属性的行为保持一致。它旨在为即将到来的提案(如 JS structs 和 WasmGC 互操作)提供固定布局保证。如果该更改被证明不兼容,则存在替代设计。
以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。
禁止向不可扩展对象添加新私有字段
阻止向不可扩展对象添加私有字段,就像我们已经阻止添加公共属性一样。
状态
阶段:3
champions:
- Mark Miller (@erights)
- Shu-yu Guo (@syg)
- Chip Morningstar (@fudco)
- Erik Marks (@rekmarks)
演讲
-
(从 Stabilize 分离出来,如 阶段 1 状态更新:希望与梦想 中所述 - 2025 年 2 月 TC39 全体会议(slides.key,slides.pdf,视频)
-
用于阶段 1 或 2 或 2.7 - 2025 年 4 月全体会议(slides.key,slides.pdf,视频)
-
阶段 2.7 状态更新 - 2025 年 7 月全体会议(slides.key,slides.pdf,视频)
-
用于阶段 3 - 2025 年 9 月全体会议(slices.key,slides.pdf,视频)
背景
如果可以向 JavaScript 对象添加新属性,则该对象是可扩展的。对象天生是可扩展的,并且可以通过 Object.preventExtensions() 使其变为不可扩展。变为不可扩展是一种方式。一旦不可扩展,对象就无法再次变为可扩展。
私有字段 不遵循对象的可扩展性。它们可以被添加到任何对象上。
例如,以下代码片段可以正常工作。
与使用属性的情况对比,后者无法正常工作。
提案
本提案建议更改不可扩展性的行为,使其也适用于私有字段。也就是说,使得私有字段不能被添加到不可扩展对象上。
对于上述示例,这意味着 new ClassWithPrivateField(42) 将抛出 TypeError,就像 new ClassWithProperty(42) 一样。
动机:固定布局保证
JS structs 提案 和 WasmGC 的 JS 互操作提案 正在添加固定布局对象。具体来说,固定布局意味着一旦对象被构造,其内存中的布局就是不可变的。
JS 语言与固定布局最接近的概念是密封,它意味着不可扩展。然而,这有一个显著的例外:私有字段不遵循不可扩展性。本提案通过提议将不可扩展性改为意味着固定布局(包括私有字段)来解决这个问题。
虽然私有字段可以通过对象外的外部存储来实现(使用 WeakMap),但这样做效率低下且缓慢。高性能的 JS 引擎将私有字段实现为对象内的内联存储,很像属性。
Champions 还认为,鉴于私有字段与属性的语法相似性,私有字段的使用暗示了内联存储。私有字段在正常情况下(忽略诸如获取属性描述符之类的元对象协议操作)的使用方式也完全镜像属性的使用方式,这表明将可扩展性扩展到包含私有字段可能符合开发者的直觉。
网络兼容性
私有字段从一开始就带有不尊重可扩展性的行为。因此,所提议的更改有非零的可能性不兼容网络。为此,Chrome 有一个使用计数器用于跟踪现实中向不可扩展对象添加私有字段的发生情况。
替代方案
如果所提议的更改不兼容网络,替代设计是创建一个称为“固定形状”的新的完整性特征,它意味着不可扩展性,并且也阻止添加私有字段。这个新特征将通过 Object.makeFixedShape() 和 Object.isFixedShape() 暴露。
这对开发者来说不太便利,因为 champions 认为开发者已经直觉地认为不可扩展性应该包含私有字段。
这对实现来说也不太理想,因为它要求对象在可扩展性之外再跟踪一位,以确定是否可以添加新的私有字段。