Skip to main content

Building Blocks in JS

Optional chaining

The Problem

Picture this: you're at a busy chai stall, trying to order your favorite masala chai. But wait! The stall owner is nowhere to be found. You can't just start brewing chai yourself, can you? That's exactly the kind of situation we find ourselves in when dealing with nested object properties in JavaScript.

Let's say we have a chaiWala object

let chaiWala = {
  name: "Sharma Ji",
  specialties: {
    masalaChai: {
      ingredients: ["tea leaves", "milk", "sugar", "spices"]
    }
  }
};

Now, if we want to access the ingredients of masala chai, we'd do:

console.log(chaiWala.specialties.masalaChai.ingredients);

But what if our chai wala decided to take a day off? In other words, what if specialties or masalaChai doesn't exist? We'd be left with an error that's hotter than freshly brewed chai:

Uncaught TypeError: Cannot read property 'ingredients' of undefined

Ouch! That's not what we were looking for!

The Old-fashioned solution: checks on top of Checks on top of Checks

Before ES2020 came to our rescue, we had to do something like this:

if (chaiWala && chaiWala.specialties && chaiWala.specialties.masalaChai) {
  console.log(chaiWala.specialties.masalaChai.ingredients);
} else {
  console.log("Sorry, no chai today!");
}

This works, but it's about as elegant as trying to drink chai with a fork. It's clunky, repetitive, and just wrong!

Optional chaining

Optional chaining is like that perfect chai stirrer - it smoothly navigates through your object properties without causing a problem. Here's how it works:

console.log(chaiWala?.specialties?.masalaChai?.ingredients);

See that little ?. sprinkled throughout? That's optional chaining in action! It's like asking politely at each step, "Hey, do you exist? No? That's cool, I'll just return undefined and be on my way."

How Does It Work?

Let's break it down, shall we? When you use ?., JavaScript checks if the property before it exists. If it does, great! Move on to the next one. If it doesn't, instead of throwing an error, it calmly returns undefined.

It's like our chai stall scenario:

  1. Is there a chaiWala? Yes? Cool, let's check if they have specialties.
  2. Are there specialties? Yep! Let's see if they make masalaChai.
  3. Is masalaChai available? Awesome! Now we can finally look at the ingredients.

If at any point the answer is "no", we just get undefined instead of an error. It's like the chai stall politely saying, "Sorry, we're closed today!" instead of yelling at you.

Optional Chaining in Action

Scenario 1:

Imagine you're building a social media app for chai lovers (ChaiChat, anyone?). You want to display a user's favorite chai, but not all users have set this preference yet.

let user = {
  name: "Chai Lover",
  preferences: {
    // Oops, no favorite chai set!
  }
};

// Without optional chaining
console.log(user.preferences && user.preferences.favoriteChai); // undefined

// With optional chaining
console.log(user.preferences?.favoriteChai); // undefined

See how much cleaner that is?

Scenario 2: The Function That may or may not exist

Let's say our chaiWala object sometimes has a brewChai method. We want to call it if it exists, but not crash our app if it doesn't.

let chaiWala = {
  name: "Sharma Ji",
  // Sometimes this method exists, sometimes it doesn't
  // brewChai: function() { console.log("Brewing chai!"); }
};

// Without optional chaining
if (chaiWala.brewChai) {
  chaiWala.brewChai();
}

// With optional chaining
chaiWala.brewChai?.(); // Nothing happens if the method doesn't exist

It's like having a polite assistant who checks if the chai is ready before trying to serve it. Smooth, right?

Ways of Optional Chaining

Just like chai comes in many varieties, so does optional chaining. Let's explore some other ways we can use it:

1. Accessing array elements

let chaiMenu = null;
console.log(chaiMenu?.[0]); // undefined

It's like trying to peek into an empty chai pot - you won't get an error, just a polite "nothing to see here"!

2. Calling Functions

let orderChai = null;
orderChai?.(); // No error, just undefined

This is super handy when you're not sure if a function exists. It's like knocking before entering - if no one's home, you just walk away.

3. Working with dynamic properties

let chaiInventory = {
  masala: 50,
  ginger: 30
};

let chaiType = "lemon";
console.log(chaiInventory?.[chaiType]); // undefined

This is perfect for when you're not sure if a property exists. It's like asking for a chai flavor - if they don't have it, you get a polite "nope" instead of a chai-tastrophe. (catastrophe)

The "Don'ts" of Optional Chaining

While optional chaining is awesome, like any good thing, it can be overused. Here are some don'ts to keep in mind:

  1. Don't use it when you expect something to exist If chaiWala should always have a name, don't do chaiWala?.name. If it's missing, you want to know about it!
  2. Don't use it in the left side of assignments
let chaiWala = null;
chaiWala?.name = "Sharma Ji"; // This won't work!

It's like trying to add sugar to a chai that doesn't exist - it just doesn't make sense!

  1. Don't overuse it to mask real errors If you find yourself using ?. everywhere, you might be hiding some real problems in your code. It's like adding extra milk to mask badly brewed chai - fix the root cause instead!

Performance: Is it like instant coffee?

Good news! Optional chaining is pretty darn fast. Modern JavaScript engines optimize it well, so you don't have to worry about it slowing down your code any more than a sprinkle of cardamom slows down your chai drinking.

However, if you're doing something performance-critical (like serving chai to a million people simultaneously), you might want to benchmark it against traditional checks.

Browser Support

Optional chaining is supported in all modern browsers, but if you need to support older versions, you might need a transpiler like Babel.

Wrapping Up:

Optional chaining in JavaScript is like that perfect cup of chai - it solves a problem smoothly, without any fuss. It makes our code cleaner, safer, and more enjoyable to write.

Let's recap the key points:

  1. Use ?. to safely access nested properties
  2. It works with properties, methods, and even array elements
  3. If something's missing, you get undefined instead of an error
  4. Don't overuse it - sometimes errors are good!
  5. It's fast and widely supported

So next time you're dealing with potentially non-existent properties, remember the optional chaining operator.

Now, if you'll excuse me, all this chai talk has made me thirsty. Time to brew a real cup!