JavaScript如何获取类自身声明字段(不含父类继承字段)
问题原因
你当前写法无法得到预期结果的核心原因是:JS类继承机制中,父类构造函数运行时的this直接指向子类创建的实例,父类里所有this.xxx = xxx的赋值操作,都会直接把属性挂载到子类实例上,成为实例的自有属性。因此直接对实例调用Object.getOwnPropertyNames(),会拿到父类、子类构造函数挂载的所有属性,无法直接区分属性归属。
实现方案
根据你是否可以修改原有类的代码,可选择以下两种实现方式:
方案1:无需修改原有类定义,通用差集过滤法
核心逻辑是先创建父类实例,拿到父类构造会挂载到实例上的全部属性,再创建子类实例取所有自有属性,过滤掉父类已存在的属性,剩下的就是子类自身声明的字段。class A { constructor() { this._a = 1; } }; class B extends A { constructor() { super(); this._b = 2; } }; function getChildClassOwnFields(Child, Parent, ...initArgs) { // 拿到父类构造挂载的所有属性 const parentIns = new Parent(...initArgs); const parentFieldSet = new Set(Object.getOwnPropertyNames(parentIns)); // 子类实例属性过滤掉父类已存在的属性 const childIns = new Child(...initArgs); return Object.getOwnPropertyNames(childIns).filter(field => !parentFieldSet.has(field)); } console.log(getChildClassOwnFields(B, A)); // 输出: [ '_b' ]注意:该方案要求父类构造函数的属性挂载逻辑是稳定的,如果父类会根据入参、外部随机状态动态挂载不同属性,判断结果会出现偏差。
方案2:可修改类定义时的精准获取法
子类构造函数中,super()调用完成的瞬间,父类所有属性挂载逻辑已经全部执行完毕,此时子类自身的属性赋值还没开始,在这个节点快照实例上已有的属性,后续新增的属性就是子类100%自有的字段,不受父类动态逻辑影响。class A { constructor() { this._a = 1; // 模拟父类动态挂载属性的场景 if (Date.now() % 2 === 0) this._randomA = 'dynamic'; } }; class B extends A { constructor() { super(); // 快照父类挂载完成后的属性集合 const parentFields = new Set(Object.getOwnPropertyNames(this)); // 子类自身属性赋值 this._b = 2; this._desc = 'class B'; // 暴露获取自有字段的方法 this.getOwnFields = () => { return Object.getOwnPropertyNames(this) .filter(field => !parentFields.has(field) && field !== 'getOwnFields'); } } }; const bIns = new B(); console.log(bIns.getOwnFields()); // 永远输出 [ '_b', '_desc' ],不受父类动态属性干扰这个方案同样兼容ES6类实例字段(写在constructor外的字段声明)的场景,这类字段的初始化逻辑恰好是在
super()执行后、constructor内代码执行前运行,会被自动归到子类自有字段中。
内容的提问来源于stack exchange,提问作者user5182503
相关产品推荐
相关产品推荐

