JS类两种属性赋值语法的差异及底层实现疑问
嘿,这个问题问到点子上了——你提到的第二种语法其实是类字段声明语法(ES2022正式纳入标准),它和传统构造函数内的属性赋值不止“动态赋值”这一点区别,咱们来逐一拆解:
一、核心差异点
初始化时机不同
传统构造函数里的this.prop = prop是在构造函数代码执行到对应行时才赋值;而类字段会在构造函数逻辑执行之前(如果是子类,则在super()调用完成后)就完成初始化。举个例子:class Foo { constructor() { console.log('构造函数执行中'); this.prop = 1; } } class Bar { prop = 2; constructor() { console.log('构造函数执行中'); } } new Foo(); // 输出:构造函数执行中 new Bar(); // 输出:构造函数执行中 // 但Bar的prop在构造函数打印前就已经被赋值为2了支持原生私有字段
类字段语法原生支持私有实例字段(用#前缀标记),这是传统构造函数赋值无法通过语法层面实现的(只能通过闭包模拟私有性,但写法繁琐且功能有限):class Bar { #privateProp = '我是私有字段'; getPrivateProp() { return this.#privateProp; } } const bar = new Bar(); console.log(bar.#privateProp); // 报错:私有字段不可外部访问 console.log(bar.getPrivateProp()); // 输出:我是私有字段子类中的约束更清晰
在子类中,如果使用构造函数赋值,必须先调用super()才能访问this;而类字段会自动在super()调用完成后初始化,不需要手动处理顺序,避免了忘记调用super()导致的错误。
二、底层实现逻辑
对于普通的公共类字段(比如你例子里的prop = 5),转译工具(如Babel)或者JavaScript引擎的处理逻辑确实和构造函数内赋值非常相似——会把类字段的初始化代码移到构造函数的最前端(子类则在super()之后)。转译后的代码大概是这样:
class bar { constructor() { this.prop = 5; } }
不过要注意:原生引擎对类字段的实现并非简单“转成构造函数赋值”,尤其是私有字段,引擎会做额外的封装来保证其私有性;但从开发者感知的逻辑层面来看,普通公共类字段的效果和构造函数内提前赋值是一致的。
另外补充个小知识点:类字段语法也支持动态赋值哦!你可以用表达式或者函数返回值来赋值,比如:
class Bar { prop = Math.random(); dynamicProp = this.getDynamicValue(); getDynamicValue() { return '动态生成的值'; } }
这样就解决了你说的“硬编码”问题~
内容的提问来源于stack exchange,提问作者Willem van der Veen

