字段装饰器是ecmascript stage 3标准特性,用于类字段初始化前的干预,通过context.initialize注入校验、转换等逻辑,不修改字段值本身,支持静态/实例/私有字段。

类字段装饰器在现代 JavaScript 中已不再是“实验性语法”,而是 ECMAScript Decorators Stage 3 提案中明确支持的核心能力之一。它不再依赖 TypeScript 的元数据反射(如 Reflect.defineMetadata),而是基于统一的 (field, context) => void 签名,专为初始化阶段介入字段行为而设计。
字段装饰器的本质是“初始化干预”
它不作用于已存在的属性值,也不拦截后续赋值(那属于访问器装饰器的职责)。它的执行时机在类定义时、字段初始化前,field 参数恒为 undefined,真正起作用的是 context —— 特别是其中的 name、static、private 和 initialize 方法。
-
不能修改字段值本身:你无法通过返回新值来替换字段,因为规范明确要求字段装饰器应返回
void -
可注册初始化逻辑:利用
context.initialize可注入字段首次赋值前的处理,比如类型校验、默认值转换或依赖绑定 -
支持静态与实例字段:通过
context.static判断,可差异化处理;私有字段(#field)也受支持,context.private为true
典型实用场景
字段装饰器的价值不在“劫持读写”,而在“声明即配置”。它让字段语义更丰富,且逻辑集中、可复用。
-
响应式字段标记:配合框架运行时,在
initialize中将字段加入响应式追踪系统,无需手动调用observe() -
自动验证与转换:例如
@required或@email,在初始化时检查值合法性,或把字符串转为Date实例 -
依赖注入标识:如
@inject('httpClient'),让 DI 容器在构造实例后自动填充该字段 -
序列化控制:搭配
@serialize({ exclude: true }),在 toJSON 逻辑中跳过该字段
写法示例(Stage 3 原生语法)
以下代码无需 TypeScript,Babel 配合 @babel/plugin-proposal-decorators(version: "2023-11" 或更新)即可运行:
function required(field, context) {<br> const { name, initialize } = context;<br> initialize(function (value) {<br> if (value == null || value === '') {<br> throw new Error(`Field '${name}' is required`);<br> }<br> return value;<br> });<br>}
class User {<br> @required name = '';<br> @required email = '';<br> age = 0;<br>}
注意:initialize 回调接收字段初始值,并可返回修正后的值;若抛出错误,实例化将中断。
与访问器装饰器的关键区别
别混淆字段(name = 'Alice')和访问器(get name() { ... })。前者只在构造时触发一次,后者每次读/写都介入。
- 要用字段装饰器做“赋值拦截”,必须配合
Object.defineProperty+ 访问器重定义 —— 这实际已超出字段装饰器本意,推荐直接使用@accessor - 字段装饰器不可用于私有字段的“运行时读写控制”,但可用于其初始化逻辑(如
#id = uuid()的生成增强) - 多个字段装饰器叠加时,按声明顺序依次执行,每个都可调用
initialize,但最终生效的是最后一个调用所返回的值











