3

This is a bit of a tricky question regarding ES6 destructuring with default usage in a javascript object constructor.

I would like to receive a destructured parameters object with default values for my object constructor

so what i did was this

function bla({a=3,b=6}={}){
  this.a=a;
  this.b=b;
  console.log(`this.a::'${this.a}' this.b::'${this.b}' a::'${a}' b::'${b}'`);
}

let myObject= new bla({a:1});
console.log(`myObject.a::'${myObject.a}' myObject.b::'${myObject.b}'`); // only a got overriden with value "1" and b remained its defauly value "6"

I know that what i did works. However, you can see that this is a bit of a code smell, because every time i need to add a new parameter to the constructor (for example {newParameter=3}) i also need to go down and add a matching line like this in the constructor body

this.newParameter=newParameter;

Is there any more elegant way to add a destructured parameter with default value which automatically is attached to "this."

3
  • One thing you can do is to give default values at the time of assignment e.g this.a = a || 3. So that you update only one line of code. Commented Aug 19, 2017 at 17:16
  • @AnuragSinghBisht: What if a is 0? You lose the provided value. Commented Aug 19, 2017 at 17:20
  • @spanky You will need to update the condition as per your need. The point was to assign default values later on if you want to update only one line of code. Commented Aug 19, 2017 at 17:24

4 Answers 4

3

I personally think your current approach is the most readable, but you can technically also do

function bla(obj = {}){
  ({
    a: this.a = 3,
    b: this.b = 6,
  } = obj);

  console.log(`this.a::'${this.a}' this.b::'${this.b}'`);
}
Sign up to request clarification or add additional context in comments.

6 Comments

But this.a = 3 will not be executed if a value of a is passed, no?
Wow, never knew that this was valid syntax. JavaScript got weird since the last time I used it. Also, I think Felix has a good point.
@FelixKling I had a typo, but the this.a is the target of the destructure, just like if you did {a: val} = obj.
@AaditMShah I had to update my example FYI, I had a mistake in there. Essentially though ({foo} = obj); is like foo = obj.foo and ({foo: bar} = obj); is like bar = obj.foo, so ({a: this.a} = obj) is just like this.a = obj.a;. Not very readable though.
Thanks for sharing this pearl. I took your example and one-upped it. You deserve an upvote.
|
0

Don't know if this is best, but you could use Object.assign.

function bla(props={}) {
  Object.assign(this, {a:3,b:6}, props);
  console.log(`this.a::'${this.a}' this.b::'${this.b}'`);
}

let myObject= new bla({a:1});

console.log(`myObject.a::'${myObject.a}' myObject.b::'${myObject.b}'`); // only a got overriden with value "1" and b remained its defauly value "6"

You lose the parameter names, but it could be argued that this is better so that you don't accidentally mutate the parameter when you meant to mutate the object property.

1 Comment

Downside: this will add potential garbage properties to this.
0

I follow more a functional style to avoid the new on object creation and this keyword.

Explanation

You could simply write a function that retuns an object and takes several arguments with default values.
Thanks of the object literal property value shorthand you have less to write.

Code

function returnObject(a = 1, b = 2, c = 3) {
  return {
    a,
    b,
    c
  }
}

console.log(returnObject())

Comments

0

If the objective is to use the variable names exactly once then this is what I'd do:

const foo = new Foo({ a: 1 });

console.log(`foo { a: ${foo.a}, b: ${foo.b} }`);

function Foo(config = {}) {
    const defaults = { a: 3, b: 6 };

    for (const [key, val] of Object.entries(defaults))
        ({ [key]: this[key] = val } = config);
}

Now, you only need to update the defaults object and you're done.


Actually, let's make a constructor constructor by abstracting this pattern:

const Foo = defcons({ a: 3, b: 6 });

const foo = new Foo({ a: 1 });

console.log(`foo { a: ${foo.a}, b: ${foo.b} }`);

function defcons(defaults) {
    return function (config = {}) {
        for (const [key, val] of Object.entries(defaults))
            ({ [key]: this[key] = val } = config);
    };
}

Now, you can easily create as many such constructors as you want.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.