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
customerblock, and guest checkouts such as order 1042 don’t have one. The Python script reads it withorder.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 asundefined, so the natural port isorder.customer.phone ?? "no phone". JavaScript stops withTypeError: Cannot read properties of undefined (reading 'phone'), the stack trace points to line 3 with the caret underphone, and the log never runs. order.customeris a missing key, so it reads asundefinedwith no error. The next step asksundefinedfor itsphone, andundefinedhas no properties, JavaScript’s word for an object’s keys, so reading one throws. Watch out: only the first missing level reads asundefined, 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.undefinedisn’t an empty object. - The optional chaining operator,
?., checks the value on its left. When that value isundefinedornull, it stops and givesundefinedfor 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 ofNonewould still break the Python chain, but?.stops onnulltoo. - The line prints
Phone: no phonefor order 1042 andPhone: +44 7700 900461for order 1043. Order 1044’s customer block has no phone, and it printsPhone: no phonetoo: 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, likeorder.billing_address, should fail loudly where it’s read, not turn intoundefinedfar 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:
order = {"id": 1042}
phone = order.get("customer", {}).get("phone", "no phone")
print(f"Phone: {phone}")