Dot Notation in a String
In this post, I am going to walk through how to access a nested property in a JavaScript object through a string
of dot-separated property names. For instance, record.user.name
should return Ben Knight
for the following object.
const record = {
user: {
name: "Ben Knight",
},
};
but first, let’s dig into some definitions.
What is dot notation?
In JavaScript, there are two core ways of accessing the properties of an object, which are aptly named Property Accessors. If you are familiar with JavaScript or Typescript you will likely be familiar with both of these notations but may not have realised that these are their names. The two styles of accessors are shown below.
const myObject = {
name: "Ben Knight",
};
// Dot notation
myObject.name;
// Bracket notation
myObject['name'];
This syntax is one of the first things you will learn about JavaScript as they are fundamental to the usage of objects and their properties or functions.
Why use a string to access properties?
At first, you may think that it is pointless to use a dot notation string like record.user.name
to access a property
but it is a powerful bit of notation that gives a lot of flexibility when creating larger and more dynamic
projects. This is because it allows you to access properties through a variable, rather than having them hard coded.
Now in a variable, we can change it at runtime to access something completely different. Why is this useful? Let’s consider the following example.
Email Templates
A common problem companies have with their software is that they need it to send out emails based on certain actions. The template of these emails often changes based on company policy, rebranding, etc so you need to make sure they can easily handle these changes so you choose to store the template in the database. You then parse these templates to add dynamic pieces such as the user’s name. But how do you do that exactly?
This is where the dot notation comes in. Here is an example email template:
Hi ${record.user.name}
You have a pending action awaiting you. Please head
to ${record.url} to action this request.
I am now able to parse this template and find two variables that need to be populated.
record.user.name
record.url
The only thing left to do is go through the object and add those values into the template before sending it.
Other examples
Email templates are only one of the many good use cases for using dot notation like this. Almost any program where you wish to have a configurable display value can use this. Some other examples are:
Display names
You may have a setting to allow a user to show their full name, first name, or name with honorifics. This could be a site-wide setting for admins or an individual one per user.
For example - given the following object, try out the dot notation field to see this in action.
const record = {
user: {
honorific: "Mr",
firstName: "Benjamin",
lastName: "Knight",
preferredName: "Ben",
},
job: {
name: "Software Developer",
company: "Playvox",
},
team: "Bens Squad",
}
Note: Anything that doesn’t parse as a valid property of the object will be used as normal text.
Dropdown Displays
Commonly, you will display a few values for a record in a dropdown. This could be configurable to allow users to prioritise different pieces of information if they find it more valuable.
Here is the object’s shape again:
const record = {
user: {
honorific: "Mr",
firstName: "Benjamin",
lastName: "Knight",
preferredName: "Ben",
},
job: {
name: "Software Developer",
company: "Playvox",
},
team: "Bens Squad",
}
How does it work?
The implementation of this code is very simple. At its core we want to do the following steps:
- Split the string by each dot. JS has the built-in
split
function for this. - for each dot, return the matching element at the given path. We can use
reduce
to do this.
Here is the simple case in code using the functions mentioned.
function dotWalk(str, obj) {
// Splits the string by each dot
return str.split('.')
// iterate the string, passing back
// the property at each path
.reduce((result, path) => {
return result[path];
// pass in the original object to begin with
}, obj);
}
This works well but there are a few things I would like to do to improve both type safety and to improve edge cases with the string. These are:
- handle cases where a property doesn’t exist gracefully
- handle trailing dots
For when a property doesn’t exist, I would like to raturn the original string so that I can easily see where these cases are.
For the case of trailing dots, I would like to return the new value and append a dot at the end as if it is the end of a sentence.
My new code now looks like:
function dotWalk(str, obj) {
// Splits the string by each dot
return str.split('.')
// iterate the string, passing back
// the property at each path
.reduce((result, path) => {
// Trailing dot case
if (path === '') return result + '.';
// Return undefined if the path doesn't exist
return result && result[path];
}, obj)
?? str; // return the original string if no property found
}
What to read more? Check out more posts below!