简体   繁体   中英

ES6 using static method to create new instance gives undefined for child class attributes

I have the following child class:

export default class File extends Model {
  selected = false
}

And the parent class:

export default class Model {
  constructor (attributes = {}) {
    if (new.target === Model) {
      throw Error('Not allowed to instantiate Model')
    }

    Object.assign(this, attributes)
  }

  static build (attributes) {
    return new this(attributes)
  }
}

I expected that when using

const file = File.build({selected: true})

the result for file.selected would have been true, but remains false. Logging "this" inside the constructor, I can see the File instance doesn't have the selected attribute at all, returning undefined.

Using the current babel config

module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        targets: {
          node: 'current'
        }
      },
      '@babel/preset-typescript'
    ]
  ],
  plugins: [
    '@babel/plugin-transform-typescript',
    '@babel/plugin-proposal-class-properties'
  ]
}

If I do not define selected on the child class, the result will then be true for file.selected

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Class_fields :

Public instance fields are added with Object.defineProperty either at construction time in the base class (before the constructor body runs), or just after super() returns in a subclass.

this.selected doesn't get set in time for the parent constructor to see it (which matches when you're allowed to use this inside a constructor). One alternative could be to put the initial value on the prototype instead:

File.prototype.selected = false;

Can you move the Object.assign to the build method instead of the constructor?

Example:

 class Model { constructor () { if (new.target === Model) { throw Error('Not allowed to instantiate Model') } } static build (attributes) { const obj = new this(attributes) Object.assign(obj, attributes) return obj } } class File extends Model { constructor() { super() this.selected = false this.defaultValue = 'default' } } const file = File.build({selected: true, foo: 'bar'}) console.log(file);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM