Locked learning resources

Join us and get access to thousands of tutorials and a community of expert JavaScript developers.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert JavaScript developers.

Unlock This Lesson

Reaching Into Nested Data With ?.

Reaching Into Nested Data With ?.

In this lesson, you ported Python’s chain of .get() calls for the customer’s phone number, and met the JavaScript operator that reads nested data safely.

  • The phone lives in a customer block, and guest checkouts such as order 1042 don’t have one. The Python script reads it with order.get("customer", {}).get("phone", "no phone"): the first .get() falls back to an empty dict, and the second asks that dict for the phone and gets its default.
  • JavaScript objects have no .get(), and a missing key reads as undefined, so the natural port is order.customer.phone ?? "no phone". JavaScript stops with TypeError: Cannot read properties of undefined (reading 'phone'), the stack trace points to line 3 with the caret under phone, and the log never runs.
  • order.customer is a missing key, so it reads as undefined with no error. The next step asks undefined for its phone, and undefined has no properties, JavaScript’s word for an object’s keys, so reading one throws. Watch out: only the first missing level reads as undefined, and the level after it throws. The error comes before ?? runs, so the default never gets a chance.
  • Python’s chain works because the first .get() hands back an empty dict, which has a .get() of its own. undefined isn’t an empty object.
  • The optional chaining operator, ?., checks the value on its left. When that value is undefined or null, it stops and gives undefined for the whole chain. Otherwise, it reads the next key, as a dot does. It checks only the value straight to its left, so any later step that can be missing needs its own.
  • With ?? after it, order.customer?.phone ?? "no phone" reads like Python’s chain, with one difference: Python’s {} default covers only a missing key, so a customer of None would still break the Python chain, but ?. stops on null too.
  • The line prints Phone: no phone for order 1042 and Phone: +44 7700 900461 for order 1043. Order 1044’s customer block has no phone, and it prints Phone: no phone too: the customer is there, so the chain reads on, and the missing phone is the first missing level.
  • Put ?. exactly where the data can be missing, and finish with ?? when you need a default.
  • Watch out for adding ?. everywhere to be safe: a required field, like order.billing_address, should fail loudly where it’s read, not turn into undefined far away.
  • ?. also works before brackets and before a method call, a topic for later.

Here’s the phone step in the Python script, with order 1042 trimmed to its ID:

Language: Python
order = {"id": 1042}

phone = order.get("customer", {}).get("phone", "no phone")
print(f"Phone: {phone}")

Locked learning resources

Join us and get access to thousands of tutorials and a community of expert JavaScript developers.

Unlock This Lesson

Already a member? Sign-In

Locked learning resources

The full lesson is for members only. Join us and get access to thousands of tutorials and a community of expert JavaScript developers.

Unlock This Lesson

Already a member? Sign-In

00:02 The courier’s form has a box for the customer’s phone number. It lives in a customer block, and guest checkouts like order 1042 don’t have one. In this lesson, you’ll port Python’s lookup for it, and meet the JavaScript operator that reads nested data safely.

00:20 Here’s the step in the Python script, with the order trimmed. There’s no customer, so the first .get() call falls back to an empty dict. The second .get() call asks that empty dict for the phone, and gets its default.

00:35 The script prints no phone.

00:39 In JavaScript, objects have no .get() method, and a missing key reads as undefined instead of raising. So the port drops both .get() calls, reads the keys with dots, and keeps the default with the nullish coalescing operator.

00:55 Run it, and JavaScript stops with a TypeError: cannot read properties of undefined, reading phone. The stack trace points to line three, with the caret under phone.

01:07 The log on line four never runs.

01:12 Read the chain one step at a time. order.customer is a missing key, so it reads as undefined, with no error. The next step asks undefined for its phone.

01:25 undefined has no properties, JavaScript’s word for an object’s keys, so reading one throws. Watch out: only the first missing level reads as undefined, and the level after it fails.

01:39 The default never gets a chance: the error comes before the nullish coalescing operator runs. Python’s chain works because the first .get() call hands back an empty dict, and a dict has a .get() method of its own. undefined isn’t an empty object, so that’s where the likeness stops.

02:00 JavaScript has an operator that means: stop here if this is missing. It’s a question mark and a dot. Put it after customer, where the data can be absent. It checks the value on its left.

02:15 When that value is undefined or null, it stops and gives undefined for the whole chain. Otherwise, it reads the next key, as a dot does.

02:26 It checks only the value straight to its left, so any later step that can be missing needs its own. For order 1042, the chain gives undefined.

02:38 The nullish coalescing operator swaps in no phone. Run it: JavaScript prints no phone, as Python does. This is the optional chaining operator. With the nullish coalescing operator after it, the line reads like Python’s chain of .get() calls.

02:58 One difference: Python’s default covers only a missing key, so a customer of None would still break the Python chain. The optional chain stops on null too.

03:11 Marta pastes each new order into the script. Order 1043 is Sam’s, and his customer block has a phone. Run both scripts: they print the same number. Order 1044 has a customer block this time, with an email but no phone.

03:30 What does JavaScript print? Your turn: pause the video and predict.

03:40 It prints no phone. The customer is there, so the chain reads on. The phone is the first missing level, so it reads as undefined. The default fills it in, as Python’s .get() call does.

03:56 Here’s the rule. Put ?. exactly where data can be missing, and add the nullish coalescing operator for a default. Watch out for adding it everywhere to be safe.

04:10 A required field, like the billing address, should fail loudly where it’s read, not turn into undefined far away.

04:17 It also works before brackets and method calls, a topic for later. Next up: Fill In the Label’s Missing Details, an exercise. A teammate’s port gets three orders wrong, and you’ll fix the address, the phone, the insured value and today’s counts, so every line matches the Python script.

Become a Member to join the conversation.