4

I've created a class and I would like to set some default options for values in case the user does not supply any arguments. I recently went from a constructor that took multiple parameters to an object because I believe it helps readability when the user is creating a new instance of the class.

Here is how I was doing it before:

module.exports = class User {
    constructor(name = "Joe", age = 47) {
        this.name = name;
        this.age = age;
    }
}

const User = require("./user");

const user = new User(); // Defaults to "Joe" and 47

In reality, my class has more parameters than that and the readability when using it becomes tough. So to solve this I switched to an options object that works much better but I can't seem to put default values. When I try to use this.name it says this.name = options.name || "Joe" Cannot read property 'name' of undefined even though I thought I set the default to "Joe"

Here is how I'm doing it now:

module.exports = class User {
    constructor(options) {
        this.name = options.name || "Joe";
        this.age = options.age || 47;
    }
}

const User = require("./user");

const user = new User();
Mr.Smithyyy
  • 2,157
  • 12
  • 49
  • 95
  • `options` is undefined, you are trying to access `undefied.name`. You could set a default of `{}` for `options` in the signature of your constructor. – clentfort Feb 13 '18 at 20:41

4 Answers4

7

You actually just need a oneliner:

const defaultUser = {
  name: "Joe",
  age: 47
};

module.exports = class User {
  constructor(options) {
     Object.assign(this, defaultUser,  options)
  }
}
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
5

You could either set a default value for options, i.e {}.

class User {
    constructor(options = {}) {
        this.name = options.name || "Joe";
        this.age = options.age || 47;
    }
}

or first check for options to be truthy and then access the value.

class User {
    constructor(options) {
        this.name = options && options.name || "Joe";
        this.age = options && options.age || 47;
    }
}
clentfort
  • 2,454
  • 17
  • 19
  • This is the ES6 way, very nice. You could also use destructuring to extract the variables from `options` :) – mhatch Feb 13 '18 at 20:48
5

If you want to change to a configuration pattern, you can still keep your default parameter syntax:

module.exports = class User {
    constructor({ name = "Joe", age = 47 } = {}) {
        this.name = name;
        this.age = age;
    }
}

const User = require("./user");

const user = new User(); // Defaults to "Joe" and 47
Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
2

Make sure you have a default for the object itself.

module.exports = class User {
    constructor(options) {
        options = options || {}
        this.name = options.name || "Joe";
        this.age = options.age || 47;
    }
}
mhatch
  • 4,441
  • 6
  • 36
  • 62
  • Ok I think I understand it now, so if options isn't specified when the class is initialized, it doesn't exist so that's why the error is being thrown? – Mr.Smithyyy Feb 13 '18 at 20:44
  • You might not want to set `options` as an instance-variable – clentfort Feb 13 '18 at 20:44
  • @clentfort I think I've seen it done this way before but I didn't understand it at the time. What is the different between this method and the first method in your answer? – Mr.Smithyyy Feb 13 '18 at 20:45
  • My first answer uses new language features, this is the "classic" way. If you want to use this code, beware that you assign `options` to the instance variable `options`, so it's available anywhere via `this.options`. This might not be desired. – clentfort Feb 13 '18 at 20:47
  • @clentfort I've updated the answer. Thanks for the comment. – mhatch Feb 13 '18 at 20:50
  • @Mr.Smithyyy The default parameter that clentfort used is ES6 syntax to do the same thing. It is very elegant, and if you are transpiling your JS I would go with that, but if you are concerned about compatibility the old school way does the exact same thing. – mhatch Feb 13 '18 at 20:54