为何ECMAScript中属性初始化无法传递给子类?
ES6类继承中属性赋值被覆盖的原因与解释
你的问题核心在于ES6类实例化过程中,父类构造函数与子类实例属性初始化的执行顺序,下面结合你的代码拆解具体逻辑:
一、ClassWithProp的情况(无自定义构造函数的子类)
当你执行new ClassWithProp(properties)时,JS引擎的执行步骤是:
- 创建子类实例对象,绑定好原型链。
- 自动调用父类构造函数
super(properties)(因为子类没有自定义constructor,JS会生成默认构造函数,直接传递参数给super)。 - 进入父类BaseClass的构造函数:通过
Object.assign(this, properties)把传入的属性值(childInitializedProp:20等)赋值给实例,这时候构造函数内的console.log能看到正确的赋值结果。 - 父类构造函数执行完毕后,子类的实例属性初始化代码会立刻执行——也就是类体里的
childUnitializedProp;(等价于给实例赋值undefined)和childInitializedProp = 1;,这两步直接覆盖了父类构造函数里已经赋好的对应属性值。 - 所以外部的
console.log(initedObj)看到的是子类初始化后的属性值,而非父类构造函数中设置的结果。
二、ClassWithOwnAssign的情况(有自定义构造函数的子类)
当执行new ClassWithOwnAssign(properties)时,执行顺序变成:
- 创建子类实例对象,绑定原型链。
- 调用
super()(这里没传参数给父类,所以父类构造函数里的Object.assign没生效)。 - 执行子类的实例属性初始化:
childUnitializedProp = undefined、childInitializedProp = 1。 - 执行构造函数中
super()之后的代码:Object.assign(this, properties),把传入的属性值赋值给实例,这时候会覆盖子类初始化的属性值。 - 所以外部
console.log能看到预期的赋值结果。
三、解决方案
如果想让父类构造函数中的赋值生效,有几种可选方式:
- 给子类添加自定义构造函数,在
super()调用后再执行Object.assign(类似ClassWithOwnAssign的写法),确保父类或外部传入的属性覆盖子类的初始值。 - 把子类的属性初始化逻辑移到构造函数中,而非类体的顶层,这样可以控制赋值顺序。
- 调整父类的赋值时机,比如在子类属性初始化完成后再执行(比如通过钩子函数)。
内容的提问来源于stack exchange,提问作者Sol
相关产品推荐
相关产品推荐

