Before the optional chaining operator (?.
) existed, it was sometimes troublesome to access deeply-nested properties in huge JavaScript objects when some of the intermediate properties might not be present.
1const john = {2 profile: {3 name: { firstName: 'John', lastName: 'Doe' },4 age: 20,5 gender: 'Male',6 },7};8
9const jane = {10 profile: {11 age: 19,12 gender: 'Female',13 },14};15
16function getFirstName(user) {17 return user.profile.name.firstName;18}
Doing getFirstName(john)
works but getFirstName(jane)
will error because the name property doesn't exist for jane.profile
.
Firstly, I encountered this code challenge at one of my interviews for a front-end position at one of the big tech companies. Once I've completed this task, I've been required to use this
get()
function in a follow-up question about string template replacement. The second time I've seen this on GreatFrontEnd.
Lodash's _.get
method was created as a solution for such use cases.
Let's write our own version as a get
function. The function gets the value at path
of object
. If the resolved value is undefined
, the `defaultValue is returned in its place. The function signature is as such:
get(object, path, [defaultValue]);
object
: The object to query.path
: The path of the property to get. It can be a string with .
as the separator between fields, or an array of path strings.defaultValue
: Optional parameter. The value returned if the resolved value is undefined
.1get(john, 'profile.name.firstName'); // 'John'2get(john, 'profile.gender'); // 'Male'3get(jane, 'profile.name.firstName'); // undefined
Arrays can also be accessed if numerical indices are provided.
get({ a: [{ b: { c: 3 } }] }, 'a.0.b.c'); // 3
There's no need to support syntax resembling get(object, 'a[0].b.c')
.
We start by checking if the object
is empty. If it is, we return the defaultValue
. Then we check if the path
is an array. If it is, we use it as is. Otherwise, we split the path
string by .
and use the resulting array.
We then iterate over the pathArray
and check if the result
is an object and if it has the value
key. If it does, we set the result
to the value of that key. Otherwise, we return the defaultValue
.
1export default function get(object, path, defaultValue) {2 if (!Object.keys(object).length) return defaultValue;3
4 const pathArray = Array.isArray(path) ? path : path.split('.');5
6 let result = object;7
8 for (let i = 0; i < pathArray.length; i++) {9 const value = pathArray[i];10
11 if (typeof result === 'object' && result !== null && value in result) {12 result = result[value];13 } else {14 return defaultValue;15 }16 }17
18 return result;19}
Sign up to get updates when I write something new. No spam ever.
Subscribe to my Newsletter