2

bsd

I have a simple object which I would like to override with another one, in case some of the properties do not exist in the object, it should be taken from a default preset object, might be deeply nested

Here is an example of the default settings object

defaults = {
   name : 'Joe',
   options : {
      color : 'green',
      dates : {
         from : new Date,
         to   : new Date,
      }
   }
}

Here is the provided object

settings = {
   name : 'David',
   options : {
      color : 'purple'
   }
}

Here is the expected result, a combination between the two...

final = {
   name : 'David',
   options : {
      color : 'purple',
      dates : {
         from : new Date,
         to   : new Date,
      }
   }
}

Is there a simple way to achieve this without using any external libraries? I have tried some approaches (JSON.stringify / parse / iterating over the objects / etc...) but couldn't get a clean solution... hopefully a oneliner

Any help would be much appreciated...

  • Did any of these answers help: https://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-deep-clone-an-object-in-javascript – Salman A Jul 12 '18 at 09:32

4 Answers4

2

Use this $.extend(true, {}, defaults,settings). Pay attention to the order of json variable. In this case, settings will override defaults should these two variables have the same attribute.

If you are looking into pure JS answer. Here is the code.

function extend(a, b){
    for (var key in b) {
        if (b.hasOwnProperty(key))
            a[key] = b[key];
            return a;
        }
    }
}
console.log(extend(defaults,settings));
david
  • 3,225
  • 9
  • 30
  • 43
  • 1
    `jQuery` was not included as the tag so notify in your post that you are using `jQuery` :) – Alex Jul 12 '18 at 09:39
  • I see. But OP did say that OP has try using `JSON.stringify`. – david Jul 12 '18 at 09:40
  • `JSON.stringify` has nothing to do with `jQuery`, it's `VanillaJS` functionality. Your answer is correct, just point out that it's using a library :) – Alex Jul 12 '18 at 09:41
1

Here is my contribution.

To note, the code is quite lengthy due to the nature of shallow & deep copying of the object.

Using Object.assign(defaults, settings), will merge your objects, but your date key will be removed as it performs a Shallow Copy of the object.

Below, I have used a snippet I have found on How to deep merge instead of shallow merge? by a user named jhildenbiddle which performs a deep merge of the object and is immutable (doesn't edit the original arrays).


let defaults = {
  name: 'Joe',
  options: {
    color: 'green',
    dates: {
      from: new Date(),
      to: new Date(),
    }
  }
};

let settings = {
  name: 'David',
  options: {
    color: 'purple'
  }
};

function mergeDeep(...objects) {
  const isObject = obj => obj && typeof obj === 'object';

  return objects.reduce((prev, obj) => {
    Object.keys(obj).forEach(key => {
      const pVal = prev[key];
      const oVal = obj[key];

      if (Array.isArray(pVal) && Array.isArray(oVal)) {
        prev[key] = pVal.concat(...oVal);
      } else if (isObject(pVal) && isObject(oVal)) {
        prev[key] = mergeDeep(pVal, oVal);
      } else {
        prev[key] = oVal;
      }
    });

    return prev;
  }, {});
}

let final = mergeDeep(defaults, settings);

console.log(final);
Alex
  • 2,164
  • 1
  • 9
  • 27
0

This might work doing it manually setting each value based if defaults have been changed.

final = {
      name : settings.name ? settings.name : "Joe",
      options {
        color: settings.color ? settings.color : "green",
        dates: {
          from : settings.dates.from ? settings.dates.from : new Date,
          to: settings.dates.to ? settings.dates.to : new Date
        }
      }
    }

This will probably work best:

var final = Object.assign({}, default, settings);
Sir Catzilla
  • 321
  • 3
  • 18
-1

You can take a look at Object.assign

final = Object.assign(defaults, settings) 
Gnujeremie
  • 570
  • 3
  • 17