Search code examples
javascriptobjectmergenesteddefault

Javascript nested objects default fallback options


I have a nested option object in javascript. What is the best way to provide default values for them?

Custom javascript object read from a json file with ajax:

{
  "fields": {
    "markdown": {
      "preview": {
        "delay": null,
        "custom": "hello"
      },
      "revisions": {
        "path": "revisions/markdown",
        "limit": 5
      }
    }
  }
}

Default options as fallback if values is not set:

{
  "fields": {
    "markdown": {
      "preview": {
        "delay": 5,
        "css": "https://example.com/my/style.css"
      },
      "revisions": {
        "path": "revisions",
        "limit": 10
      }
    }
  }
}

Expected results

Keep everything from custom object and complete it with default values, "css" in this case.

{
  "fields": {
    "markdown": {
      "preview": {
        "delay": null,
        "css": "https://example.com/my/style.css",
        "custom": "hello"
      },
      "revisions": {
        "path": "revisions/markdown",
        "limit": 5
      }
    }
  }
}

Notes:

  • The custom object may not include all the nested values. If values are missing default value should apply.
  • Null, empty and 0 is accepted values and should not be overwritten by default values.
  • Values in the custom object that is missing as default values makes no harm and does not need to be dealt with.

What I've tried to far


Solution

  • You could take a recursive approach by checking the value of the object, if an object and check the nested objects or assign the value if the key does not exist.

    function update(object, fallback) {
        Object
            .entries(fallback)
            .forEach(([k, v]) => {
                if (v && typeof v === 'object') {
                    update(object[k] = object[k] || (Array.isArray(v) ? [] : {}), v);
                } else if (!(k in object)) {
                    object[k] = v;
                }
            });
    }
    
    var object = { fields: { markdown: { preview: { delay: null, custom: "hello" }, revisions: { path: "revisions/markdown", limit: 5 } } } },
        fallback = { fields: { markdown: { preview: { delay: 5, css: "https://example.com/my/style.css" }, revisions: { path: "revisions", limit: 10 } } } };
    
    update(object, fallback);
    
    console.log(object);
    .as-console-wrapper { max-height: 100% !important; top: 0; }