7.4 Implementing generic deep updating

The following function implements generic deep updating.

  1. function deepUpdate(original, keys, value) {
  2. if (keys.length === 0) {
  3. return value;
  4. }
  5. const currentKey = keys[0];
  6. if (Array.isArray(original)) {
  7. return original.map(
  8. (v, index) => index === currentKey
  9. ? deepUpdate(v, keys.slice(1), value) // (A)
  10. : v); // (B)
  11. } else if (typeof original === 'object' && original !== null) {
  12. return Object.fromEntries(
  13. Object.entries(original).map(
  14. (keyValuePair) => {
  15. const [k,v] = keyValuePair;
  16. if (k === currentKey) {
  17. return [k, deepUpdate(v, keys.slice(1), value)]; // (C)
  18. } else {
  19. return keyValuePair; // (D)
  20. }
  21. }));
  22. } else {
  23. // Primitive value
  24. return original;
  25. }
  26. }

If we see value as the root of a tree that we are updating, then deepUpdate() only deeply changes a single branch (line A and C). All other branches are copied shallowly (line B and D).

This is what using deepUpdate() looks like:

  1. const original = {name: 'Jane', work: {employer: 'Acme'}};
  2. const copy = deepUpdate(original, ['work', 'employer'], 'Spectre');
  3. assert.deepEqual(copy, {name: 'Jane', work: {employer: 'Spectre'}});
  4. assert.deepEqual(original, {name: 'Jane', work: {employer: 'Acme'}});