Julián Bonilla
Julián Bonilla

Reputation: 385

Set attributes to a class from constructor parameters in a clean way

I have this code for a class that receives some parameters, and I'm assigning them as object properties once each time.

class InitAnimation {
  constructor(settingsAnimation, settingButton, isHelp, isEnd) {
    // Initialized the configuration for  main animation.
    this.settingsAnimation = settingsAnimation;
    this.settingButton = settingButton;
    this.yes = null;
    this.no = null;
    this.isHelp = isHelp;
    this.isEnd = isEnd;
    this.initConfig();
  }

Is there a cleaner way to do this in ES6, in which I just can take the arguments key-values and assign them to the object as computed property names? Something like:

class InitAnimation {
  constructor(settingsAnimation, settingButton, isHelp, isEnd) {
    // Initialized the configuration for  main animation.
    // I know this doesn't work on 'arguments'
    arguments.forEach(key => this[key] = arguments[key]);
    this.initConfig();
}

For this case I can't modify the way parameters are sent because that would imply changing everyone else's code and the project is kinda big right now. Can I do this in a better way without changing how parameters are passed?

Upvotes: 2

Views: 2811

Answers (4)

user3136781
user3136781

Reputation: 91

Given constructor options are wrapped in an object, which I personally prefer not to mess up the arguments order:

const pet = new Feline({breed, age, sex})

you can easily assign them inside the class:

class Feline {
    constructor(args) {
        Object.assign(this, args)
    }
    ...
  }

Typescript and intellisence will likely hate it, but in an environment without TS it's quick and dirty fix to pass as much stuff as you need inside a class.

enter image description here

Upvotes: 0

Estus Flask
Estus Flask

Reputation: 222474

There are several options here.

Object literal can be used to assign properties. This results in copying and pasting parameters in order to enumerate them explicitly but results in more solid code and function signature that can be statically analyzed:

  constructor(foo, bar) {
    Object.assign(this, { foo, bar });
    ...
  }

Arguments can be processed according to parameter list. This results in parameter list that is enumerated once, but function signature is loose, it cannot be statically analyzed and is prone to human errors:

  constructor(...args) {
    ['foo', 'bar']
    .forEach((paramName, i) => {
      this[paramName] = args[i];
    });
  }

It should be noticed that this is efficiently solved in TypeScript with parameter properties and is one of the reasons why it can be chosen over vanilla JavaScript:

constructor(public foo) {}

is syntactic sugar for

constructor(foo) {
  this.foo = foo;
}

Upvotes: 3

Duncan Thacker
Duncan Thacker

Reputation: 5188

You can detect the names of a function's arguments using this technique:

https://davidwalsh.name/javascript-arguments

So you could apply that to your constructor, then use a loop to match up the argument names with their values (by index) and then apply them to an object.

function argumentsToObject( func, args ) {
   const argNames = getArgumentNames( func ); //use the code from the above link to do this
   const resultObject = {};
   argsNames.forEach( ( argName, index ) => {
      var argValue = args[index];
      resultObject[ argName ] = argValue;
   });
}

Then in your constructor, do

const argsObject = argumentsToObject( InitAnimation.prototype.constructor, arguments );
//copy all the arguments onto this
Object.assign( this, argsObject );

Upvotes: 1

T.J. Crowder
T.J. Crowder

Reputation: 1074295

Yes, in ES2015+ you can use Object.assign and shorthand properties:

constructor(settingsAnimation, settingButton, isHelp, isEnd) {
  // Initialized the configuration for  main animation.
  Object.assign(this, {settingsAnimation, settingButton, isHelp, isEnd});
  this.yes = null;
  this.no = null;
  this.initConfig();
}

Live Example:

class InitAnimation {
    constructor(settingsAnimation, settingButton, isHelp, isEnd) {
      // Initialized the configuration for  main animation.
      Object.assign(this, {settingsAnimation, settingButton, isHelp, isEnd});
      this.yes = null;
      this.no = null;
      this.initConfig();
    }
    initConfig() {
    }
}
const a = new InitAnimation("a", "b", "c", "d");
console.log(a);

Upvotes: 5

Related Questions