Free JavaScript reference · Python timeline
JavaScript ES2020: Safer optional access and larger integers
Optional chaining, nullish defaults, BigInt, and allSettled make absence and asynchronous outcomes more explicit.
Edition 11 · Published · Editorial review October 26, 2026
Standardized in ES2020 · Syntax
Optional chaining with ?.
Optional chaining stops an access chain when the current receiver is null or undefined, producing undefined. It is useful for optional nested records and callbacks. It does not stop for every falsey value.
A chain does not prove a value has the right type. An optional call still fails if a present property is not callable. The root identifier must also exist; optional chaining is not a way to refer to an undeclared variable.
The example combines optional access with a separate defaulting decision. Keep chains continuous: grouping an intermediate result can end the short-circuiting behavior.
Worked example
Uses ES2020 features · Script
const profile = {contact: null}; console.log(profile.contact?.email ?? "not supplied"); const callback = undefined; console.log(callback?.() === undefined);
Expected output
not supplied
true
Example checked with Chromium 151.0.7922.34, Node.js 24.19.0.
Common mistake
Optional chaining is not input validation, and it cannot be an assignment target. A present non-function still throws when called.
Try it yourself
Change contact to {email: ""}. Predict the result and explain why the empty value is preserved.
Read more: ES2020 specification · MDN explanation and compatibility
Standardized in ES2020 · Syntax
Nullish defaults with ??
?? selects its right operand only when the left value is null or undefined. This differs from ||, which also replaces zero, false, and empty strings. Choose according to the data model's definition of absence.
The right operand is evaluated only when needed. Use parentheses when combining ?? with && or ||; JavaScript rejects an unparenthesized mixture to avoid ambiguous-looking code.
The example preserves an explicit zero retry count while supplying a value for an absent setting. Defaults and validation remain separate: a negative number is not absent simply because it is invalid.
Worked example
Uses ES2020 features · Script
console.log(0 ?? 3); console.log(0 || 3); console.log(null ?? "fallback"); console.log(JSON.stringify("" ?? "fallback"));
Expected output
0
3
fallback
""
Example checked with Chromium 151.0.7922.34, Node.js 24.19.0.
Common mistake
Do not use ?? as a range or type check. It handles only null and undefined.
Try it yourself
Predict the results for false, NaN, and undefined with both || and ??.
Read more: ES2020 specification · MDN explanation and compatibility
Standardized in ES2020 · Built-in type
BigInt represents large integers
BigInt represents integers beyond Number's safe integer range. Add an n suffix to an integer literal or construct a value from an exact integer string. Arithmetic stays in the BigInt domain.
Do not first convert a large decimal string to Number and then to BigInt: precision might already have been lost. Number and BigInt arithmetic cannot be freely mixed, and division truncates toward zero.
BigInt is not a decimal-money type. Standard JSON.stringify also rejects it unless you deliberately define a serialization strategy.
Worked example
Uses ES2020 features · Script
const id = 9007199254740993n; console.log(String(id + 2n)); console.log(String(7n / 2n)); try { JSON.stringify({id}); } catch { console.log("choose a JSON representation"); }
Expected output
9007199254740995
3
choose a JSON representation
Example checked with Chromium 151.0.7922.34, Node.js 24.19.0.
Common mistake
Writing a large Number literal before converting to BigInt can preserve the already-rounded value rather than the intended integer.
Try it yourself
Construct the identifier from a string, then compare with BigInt(Number(theString)). Why can the results differ?
Read more: ES2020 specification · MDN explanation and compatibility
Standardized in ES2020 · Built-in async API
Promise.allSettled() keeps every outcome
allSettled waits for each supplied input to fulfill or reject, then returns an ordered list of outcome records. It is useful for independent work where one failure should not erase the useful results of other operations.
Result order matches input order rather than completion order. A fulfilled record has value; a rejected record has reason. Treat these shapes separately instead of assuming every item has a value.
This operation reports outcomes; it does not turn a failed operation into a successful one or decide whether the overall workflow should proceed.
Worked example
Uses ES2020 features · Script
const finished = Promise.allSettled([ Promise.resolve(4), Promise.reject("missing") ]).then(results => { console.log(results.map(result => result.status).join(", ")); console.log(results[0].value, results[1].reason); });
Expected output
fulfilled, rejected
4 missing
Example checked with Chromium 151.0.7922.34, Node.js 24.19.0.
Common mistake
allSettled does not cancel work or limit how much is started. Handle failures deliberately after collecting the outcomes.
Try it yourself
Compare this example with Promise.all and predict which information reaches a success handler.
Read more: ES2020 specification · MDN explanation and compatibility
Recap
Optional chaining, nullish defaults, BigInt, and allSettled make absence and asynchronous outcomes more explicit. Check the engines your project supports before adopting new syntax or built-ins.
Read the ES2020 specification →