Leonardo Alves
Leonardo Alves

Reputation: 1946

ES6 Classes Default Value

Is it possible to create a ES6 class, that assigns a default value to a property if it's not passed in the new method?

class myClass {
    constructor(options) {
        this.a = typeof options.a !== 'undefined' ? options.a : 'default a value';
        this.b = typeof options.b !== 'undefined' ? options.b : 'default b value';
        this.c = typeof options.c !== 'undefined' ? options.c : 'default c value';
    }
}

var myClassWithValue = new myClass({a:'a value', b: 'b value'});

If I try to do this with this code, compiling with babeljs, I get a TypeError: Cannot set property 'c' of undefined.

Maybe I am not getting how classes work in javascript.

Upvotes: 38

Views: 72074

Answers (13)

MKM
MKM

Reputation: 1

class myClass {
  constructor(
  a = 'default a value',
  b = 'default b value',
  c = 'default c value'
  ) {
      this.a = a;
      this.b = b;
      this.c = c;
    }
}

let myClassWithValue = new myClass('a value','b value');

console.log(myClassWithValue);

Upvotes: 0

Gagik
Gagik

Reputation: 169

I propose this solution with OR operator, this seems more readable and easy to maintain, no need to define default value for option variable.

class myClass {
  constructor(options) {
    this.a = options.a || 'default a value';
    this.b = options.b || 'default b value';
    this.c = options.c || 'default c value';
  }
}

var v = new myClass({
  a: 'a new value',
  b: 'b new value'
});

   // to test 
console.log(v);

Upvotes: 1

I build this. I think it is the easiest way to read the code in this problem.

class myClass {

    constructor(options){

        let default_values ={
            a: '',
            b: '',
            c: ''
        }
        options = {...default_values, ...options}

        this.a = options.a;
        this.b = options.b;
        this.c = options.c;
    }
}

Upvotes: -1

sergo911
sergo911

Reputation: 31

I made a small correction: Replaced the large object with Object()

class SomeClass {
  constructor({a = 'defA', b = 'defB', c = 'defC'} = Object()) { 
    this.a = a;
    this.b = b;
    this.c = c; }
}
console.log(new SomeClass ({a:'a', b:'b', c:'c'}))
console.log(new SomeClass ({a:'a', c:'c'}))

(Node REPL) Output:

SomeClass { a: 'a', b: 'b', c: 'c' }
SomeClass { a: 'a', b: 'defB', c: 'c' }

Upvotes: 0

Nikola Mitic
Nikola Mitic

Reputation: 1492

If you would like to have some properties default but some not you can use also use spread operator (work as same as Object.assign answer)

const defaults = {someDefault: true};

class SomeClass {
    constructor(config) {
        this.config = {...defaults, ...config};
    }
}

Upvotes: 9

Lucas Breitembach
Lucas Breitembach

Reputation: 1683

if there is no parameter passing through the constructor, it is assigned a default value as it was pre-set, I hope I have helped!

class User {
  constructor(fullName = "fooName", lastName, canAccess = false) {
    this.fullName = fullName;
    this.lastName = lastName;
    this.canAccess = canAccess;
  }
}

Upvotes: 6

ElrohirGT FAGD
ElrohirGT FAGD

Reputation: 17

So I've been reading to the answers to this question and I haven't found one that works easily with extended classes, so I came up with this.

First you create a function that checks if an object has the properties of another object:

function checkValues(values = {}, targets) {
  values = Object.keys(values);
  targets = Object.keys(targets);
  return values.every(keyValor => targets.includes(keyValor));
}

Then in a class you define the default values like this:

class Error {
  constructor(options = {}) {
    //Define default values
    var values = {
      title: '',
      status: 500,
      mesagge: ''
    };
    //Check if options has properties of values
    var valid = checkValues(values, options);
    //If options doesn't has all the properties of values, assign default values to options
    if (!valid) {
      options = valores
    }
    //Asign options to the class
    Object.assign(this, options);
  }
}

So now, if you want to have a child class you just need to declare the default values for that child class:

class FormError extends Error{
  constructor (options = {}){
    var values = {
      invalidParams: [{name:'', reason: ''}]
    };
    var valid = checkValues(values, options);
    if (!valid) { options = values}
    super(options);
    Object.assign(this, options);
  }
}

EXAMPLE:

var a = new Error();
var b = new FormError();
var c = new FormError({invalidParams: [{name: 'User', reason: 'It has to be a string!'}]});
console.log(a, b, c);

Note: It only works if you want to have ALL the defaults values and not just some of them, for example:

var e = new Error({message: 'This is an error'});
console.log(e.message);// ''
//Error e will only have the default values, and message would be empty.

var h = new FormError({title: 'FORM ERROR', status: 400});
console.log(h.title);//''
//Error h will only have the defaults because I didn't provide 'invalidParams'

Upvotes: 0

rich remer
rich remer

Reputation: 3577

I'd just add it to the prototype. ES6 classes are just syntactic sugar, so you can use all the standard prototypal inheritance techniques that were available before the introduction of the class keyword.

const {assign, seal} = Object;

class MyClass {
    constructor(options) {
        assign(seal(this), options);
    }
}

assign(MyClass.prototype, {
    a: "default a value",
    b: "default b value",
    c: "default c value"
});

Upvotes: 0

AESTHETICS
AESTHETICS

Reputation: 1049

Shorter and cleaner version based on Default parameters from MDN web docs.

class myClass {
  constructor(
  a = 'default a value',
  b = 'default b value',
  c = 'default c value'
  ) {
      this.a = a;
      this.b = b;
      this.c = c;
    }
}

let myClassWithValue = new myClass('a value','b value');

console.log(myClassWithValue);

With passing an Object.

class myClass {
  constructor({
  a = 'default a value',
  b = 'default b value',
  c = 'default c value'
  }) {
      this.a = a;
      this.b = b;
      this.c = c;
    }
}

let options = {
  a: 'a value',
  b: 'b value'
}

let myClassWithValue = new myClass(options);

console.log(myClassWithValue);

Upvotes: 4

aleha_84
aleha_84

Reputation: 8539

Object.assign works for me as well

class RenderProperties {
   constructor(options = {}){
        Object.assign(this, {
            fill : false, 
            fillStyle : 'rgba(0, 255, 0, 0.5)',
            lineWidth : 1,
            strokeStyle : '#00FF00'
        }, options);
    }
}

Upvotes: 33

pkloss
pkloss

Reputation: 41

I just asked a similar question and found this question after I came up with a solution, so I thought I'd post it here as well.

My question was specific to ES6 and using deconstruction to setting up parameter defaults for a class. It seems the spec doesn't allow you to directly deconstruct arguments unless you do something similar to what @Jaromanda X did.

I wanted something shorter and cleaner, and ended up using the following pattern:

class Test {
    constructor(options) {
      let {
        defaultOne   : defaultOne   = 'default one value', 
        defaultTwo   : defaultTwo   = 'default two value', 
        defaultThree : defaultThree = 'default three value'
      } = (options) ? options:{};

      this.defaultOne   = defaultOne;
      this.defaultTwo   = defaultTwo;
      this.defaultThree = defaultThree;

      this.init();
    }

  init() {
    console.log(this.defaultOne);
    console.log(this.defaultTwo);
    console.log(this.defaultThree);
  }
}

new Test({defaultOne: 'Override default one value'});
new Test();

ES6 Babel test

Compiled Babel ES5

All we're doing here is deconstructing the options argument, and we handle the undefined use case with a ternary.

Upvotes: 0

Jaromanda X
Jaromanda X

Reputation: 1

If you're going to use ES6, why not use all of ES6, i.e. default values for parameters and destructuring assignment

class myClass {
  constructor({a = 'default a value', b = 'default b value', c = 'default c value'} = {a:'default option a', b:'default option b', c:'default option c'}) {
    this.a = a;
    this.b = b;
    this.c = c;
  }
}
var v = new myClass({a:'a value', b: 'b value'});
console.log(v.toSource());
var w = new myClass();
console.log(w.toSource());

http://www.es6fiddle.net/ibxq6qcx/

edit: also tested and confirmed to run on https://babeljs.io/repl/

Upvotes: 49

Mathieu Dutour
Mathieu Dutour

Reputation: 549

I would suggest the following:

class myClass {
  constructor(options) {
    const defaults = {
      a: 'default a value',
      b: 'default b value',
      c: 'default c value'
    };
    const populated = Object.assign(defaults, options);
    for (const key in populated) {
      if (populated.hasOwnProperty(key)) {
        this[key] = populated[key];
      }
    }
  }
}

var myClassWithValue = new myClass({a:'a value', b: 'b value'});

Upvotes: 6

Related Questions