Skip to content

Instantly share code, notes, and snippets.

@LukeChannings
Created December 2, 2015 13:06
Show Gist options
  • Save LukeChannings/15c92cef5a016a8b21a0 to your computer and use it in GitHub Desktop.
Save LukeChannings/15c92cef5a016a8b21a0 to your computer and use it in GitHub Desktop.
// ensure the keys being passed is an array of key paths
// example: 'a.b' becomes ['a', 'b'] unless it was already ['a', 'b']
const keys = ks => Array.isArray(ks) ? ks : ks.split('.')
// traverse the set of keys left to right,
// returning the current value in each iteration.
// if at any point the value for the current key does not exist,
// return the default value
const deepGet = (o, kp, d) => keys(kp).reduce((o, k) => o && o[k] || d, o)
// traverse the set of keys right to left,
// returning a new object containing both properties from the object
// we were originally passed and our new property.
//
// Example:
// If o = { a: { b: { c: 1 } } }
//
// deepSet(o, ['a', 'b', 'c'], 2) will progress thus:
// 1. c = Object.assign({}, {c: 1}, { c: 2 })
// 2. b = Object.assign({}, { b: { c: 1 } }, { b: c })
// 3. returned = Object.assign({}, { a: { b: { c: 1 } } }, { a: b })
const deepSet = (o, kp, v) =>
keys(kp).reduceRight((v, k, i, ks) =>
Object.assign({}, deepGet(o, ks.slice(0, i)), { [k]: v }), v)
@LukeChannings
Copy link
Author

deepGet(o : Object, kp : string | Array, d : any)

o (object)

An object from which to pluck a value

kp (key path)

a path to a value, specified as dot notation or a list of path components.

d (default)

a default value to return in case the value does not exist. Default is undefined.

Usage:

const data = {
  a: {
    b: {
      c: 123
    }
  }
}

deepGet(data, 'a.b.c') // 123

deepSet(o : Object, kp : string | Array, v : any)

o (object)

An object to base our new object on

kp (key path)

a path to a value, specified as dot notation or a list of path components.

v (value)

the new value at the key path

Usage:

const data = {
  a: {
    b: {
      c: 123,
      d: {
        e: Symbol('foo')
      }
    }
  }
}

const newData = deepSet(data, 'a.b.c', 456)

newData === data // false
newData.a.b === data.a.b // false
newData.a.b.d === data.a.b.d // true

From the above outputs we can see the new object is not a deep clone of all objects,
only the values along the keypath are different.

@Karolusrex
Copy link

Thanks a big bunch!

@PEZO19
Copy link

PEZO19 commented Aug 14, 2021

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment