0

Coming from an old-school way of handling my defaults, I am trying to wrap my head around how to allow default values within an object literal for a constructor, while calling the constructor with a partial object literal. Note: I am still not a fan of "class" syntax for constructors, but I intend to use it, so please indulge me while I learn!

Code speaks louder than words. Here was my first attempt:

class ProxyManager {
    constructor(
        proxy = {
            proxyID: 12345,
            proxyHost: '',
            proxyPort: 8080,
            proxySSL: false,
            proxyPath: ''
        }
    ) {
        this.proxy = proxy;

    }

    getProxy() {
        return this.proxy;
    }
}

const foo = new ProxyManager();
foo.getProxy(); // returns the full default object defined in the constructor

const bar = new ProxyManager({proxyID: 67890});
foo.getProxy(); // returns {proxyID: 67890}

None of this is a surprise; you can see right from the syntax that as long as something is passed in as the first paramater, it becomes "proxy". So, while I wasn't expecting it to work, it was my starting point.

Out of familiarity, I fell back to an older-school way of doing it, which is something like this:

class ProxyManager {
    constructor(proxy) {
        this.proxy = proxy || {};

        const defaults = {
            proxyID: 12345,
            proxyHost: '',
            proxyPort: 8080,
            proxySSL: false,
            proxyPath: ''
        }

        // swap in more thorough sanity-check if needed
        if (Object.prototype.toString.call(this.proxy) === '[object Object]') {
            this.proxy = Object.assign(defaults, this.proxy)
        }

    }

    getProxy() {
        return this.proxy;
    }
}

const foo = new ProxyManager();
foo.getProxy(); // returns the full default object defined in the constructor

const bar = new ProxyManager({proxyID: 67890, proxyPort: 16500});
foo.getProxy(); // returns full object with updated proxyID and proxyPort

It works, and I guess I could move on... but I am interested to see if there is a pattern I'm missing. I did some searching, and kept coming up short.

Greg Pettit
  • 10,749
  • 5
  • 53
  • 72
  • 1
    There is nothing old-school about second approach (other than using `$.extend` instead of the standard `Object.assign` :-P) – Bergi Sep 28 '20 at 06:26
  • 1
    This has nothing to do with class syntax specifically, it's all about default parameters. If you wanted to use defaults for individual properties, you would have to use destructuring (and it would look like e.g. [this](https://stackoverflow.com/a/26578323/1048572)), but then you'd need to put the properties back together into an object separately. – Bergi Sep 28 '20 at 06:30
  • I came across some of the destructuring examples, but I admit that they lost me. I missed the step of needing to put the properties back together into an object to make it work as intended. If it scans poorly, I'm probably better off sticking to the familiar. – Greg Pettit Sep 28 '20 at 06:32

1 Answers1

1

Based on comments, option #2 in the original question isn't such a bad solution. It's probably better than the following. But just to be thorough, here's what we arrived at:

class ProxyManager {
    constructor(
        {
            proxyID = 12345,
            proxyHost = '',
            proxyPort = 8080,
            proxySSL = false,
            proxyPath = ''
        } = {}
    ) {
        
    this.proxy = {
            proxyID,
            proxyHost,
            proxyPort,
            proxySSL,
            proxyPath
        }

    }

    getProxy() {
        return this.proxy;
    }
}

It's possibly harder to grok for older-school JS users like me, and it is certainly needlessly repetitive for the end result. But it fits my original question criteria, so here it is as an answer. As a side benefit, you don't have to do a bunch of sanity-checks to ensure the defaults work. If the constructor is called with invalid paramaters (for example, passing in a simple string or int), the defaults just apply. On the other hand, that's also the drawback... there's no warning that you have used the constructor incorrectly.

Greg Pettit
  • 10,749
  • 5
  • 53
  • 72
  • 1
    Yes, needlessly repetitive. I would recommend to avoid destructuring unless you actually want to refer to the properties individually, not as an object. (Or if you care a lot about the set of properties the new object should have - with `Object.assign` the caller could pass in anything). – Bergi Sep 28 '20 at 18:30
  • 1
    Nah, I don't care a lot. The amount that I care is managed by a separate sanity-checking function. I've gone with option #2 of the original question (ish; obviously the production code is more than that), but wanted to put this here for completion's sake. :-) Thanks for your help, Bergi! – Greg Pettit Sep 28 '20 at 21:38