DEV Community

loading...

Get Nested Property from a Object in JS

Jitesh Dhamaniya
Full Stack Developer.
・1 min read

Recently Stumbled upon this nice snippet for accessing Nested property using String.

/**
 * get property of object
 * @param obj object
 * @param path e.g user.name
 */
function getProperty(obj, path, defaultValue = '-') {
    const value = path.split('.').reduce((o, p) => o && o[p], obj);

    return value ? value : defaultValue;
  }
Enter fullscreen mode Exit fullscreen mode

and this how you use it

getProperty(object, 'passengerDetails.data.driverInfo.currentVehicle.vehicleType')
Enter fullscreen mode Exit fullscreen mode

Reference
https://stackoverflow.com/a/64239231/11164153

Would be interested to learn if there is any other easier or better way.

Discussion (1)

Collapse
tominoff profile image
Tominov Sergey • Edited

I think you should never use naive boolean conversion for such things because JS has at least 6 falsy types which can be used as regular values. This function you showed, gives you false positive result when you try extract that kind of values:

const obj = { 
  a: { 
    b1: false, 
    b2: null, 
    b3: undefined, 
    b4: NaN, 
    b5: 0, 
    b6: ''
  } 
}

getProperty(obj, 'a.b1') // '-'
getProperty(obj, 'a.b2') // '-'
getProperty(obj, 'a.b3') // '-'
getProperty(obj, 'a.b4') // '-'
getProperty(obj, 'a.b5') // '-'
getProperty(obj, 'a.b6') // '-'
Enter fullscreen mode Exit fullscreen mode

Instead of naive boolean conversions to check if object property exists always use .hasOwnProperty.👍 As a possible solution for your needs (return some defaults if path is incorrect) you can use symbols:

const NOT_FOUND_SYMBOL = Symbol('function:getProperty:notFound')

function getProperty (obj, path, defaultValue = '', pathDelimiter = '.') {
  const pathValue = path
    .split(pathDelimiter)
    .reduce((prev, curr) => {
      // when not found we don't need to go deeper, kind of early exit
      return (prev !== NOT_FOUND_SYMBOL && prev.hasOwnProperty(curr)) 
        ? prev[curr] 
        : NOT_FOUND_SYMBOL
    }, obj)

  return pathValue !== NOT_FOUND_SYMBOL ? pathValue : defaultValue
}

const obj = {
  a: { b: { 
    c1: null,
    c2: false,
    c3: NaN,
    c4: '',
    c5: 0,
    c6: undefined,
    c7: `It's ok`
  }}
}

console.log(getProperty(obj, 'a.b.c0', 'Path is incorrect')) // 'Path is incorrect'
console.log(getProperty(obj, 'a.b.c1', 'Path is incorrect')) // null
console.log(getProperty(obj, 'a.b.c2', 'Path is incorrect')) // false
console.log(getProperty(obj, 'a.b.c3', 'Path is incorrect')) // NaN
console.log(getProperty(obj, 'a.b.c4', 'Path is incorrect')) // ''
console.log(getProperty(obj, 'a.b.c5', 'Path is incorrect')) // 0
console.log(getProperty(obj, 'a.b.c6', 'Path is incorrect')) // undefined
console.log(getProperty(obj, 'a.b.c7', 'Path is incorrect')) // "It's ok"
Enter fullscreen mode Exit fullscreen mode