Handbooks / JavaScript / Chapter 5

Modern JavaScript Features

7 pages · ~5 min✓ Reviewed

Builds on Event Loop and Async.

JavaScriptPage 1

Modern JS Mental Model

1. Unpack, spread, collect

  • Arrays unpack by position
  • Objects unpack by key
  • ... is spread or rest, by where it sits
javascript
const [a, b] = arr;
const { x, y } = obj;
const copy = [...arr, 5];
const [first, ...others] = arr;
SpreadRest
Directionexpands outcollects in
Takesiterable or objectremaining items
Givesseparate elementsone array or object

2. Safe access

  • ?. short-circuits to undefined when the left is null or undefined
  • Without it: TypeError
  • ?? returns the right side only for null or undefined
javascript
const city = user?.address?.city ?? 'N/A';

undefined from ?. falls through to ??

3. Template literals

  • Backticks: Hi ${name}
  • ${} embeds any expression
  • Strings can span multiple lines
Remember

count ?? 10 keeps 0; only null and undefined fall back.

JavaScriptPage 2

Destructuring, Spread and Rest in Practice

1. Rename, Default, Nest

  • { id: userId } renames the key to userId
  • role = 'guest' applies only when the value is undefined
  • null, 0 and '' keep their value, no default
  • Nested { address: { city } } throws if address is undefined
javascript
const { id: userId, role = 'guest' } = user;
const { address: { city } } = user;

2. Rest and Spread

RestSpread
Doescollects the remainingexpands into elements
Positionlast onlyanywhere
Example[first, ...others][...a, ...b]
  • const { a, ...remaining } = obj collects the other keys
  • { ...obj, k: 1 } is a shallow copy: nested objects are shared
  • Later keys override earlier ones in { ...a, ...b }

3. Swap and Mistakes

  • [a, b] = [b, a] swaps two variables with no temp
Rest goes last

[...others, last] is a SyntaxError. Rest collects what is left, so nothing can follow it.

JavaScriptPage 3

Optional Chaining, ?? and Template Literals

1. Safe access and ??

  • obj?.prop, obj?.[key], fn?.(args)
  • Broken link gives undefined, no throw
  • Guards only the part left of ?.: a?.b.c throws if b is undefined
||??
Replacesevery falsy value (0, '', false)only null, undefined
count = 0gives 10keeps 0
  • a ?? b || c is a SyntaxError; add parentheses
  • x ??= v assigns only if x is null or undefined

2. Template literals

  • Untagged: ${} values become strings, so objects print [object Object]
  • Tagged: the tag gets the string parts, then the raw values unconverted
javascript
const tag = (s, v) => typeof v;
console.log(tag`a${{}}b`);
console.log(`a${{}}b`);
output
object
a[object Object]b

3. Interview Point

  • Why does a?.b.c throw? ?. guards only its left side.
  • Result of 0 ?? 10? 0; || gives 10.
  • Tagged vs plain ${}? The tag gets raw values; plain converts to strings.
JavaScriptPage 4

Array Methods: map, filter, reduce

1. What each one does

MethodReturnsCallback
mapnew array, same lengthtransforms each item
filternew array, maybe shorterkeeps items when truthy
reduceone value(acc, item) => next, initial
  • Always pass the initial value to reduce
  • [].reduce(fn) with no initial throws TypeError

2. Callback forms and chaining

  • Callback gets (item, index, array)
  • Gotcha: ['1','2','3'].map(parseInt) gives [1, NaN, NaN]
  • index is passed to parseInt as the radix
javascript
const total = orders
  .filter(o => o.paid)
  .map(o => o.total)
  .reduce((s, t) => s + t, 0);

paid orders only, then totals, then sum

3. Mutation and mistakes

Original arrayMethods
Untouchedmap, filter, reduce
Mutatedsort, push, splice, reverse
  • map only for side effects: use forEach
  • reduce callback that forgets to return acc
reduce rule

Pass an initial value and return the accumulator every step.

JavaScriptPage 5

ES Modules and Map and Set

1. Exports and Imports

  • export const f = 1 pairs with import { f } from './m.js': exact name in braces
  • Default: import any from './m.js', any name; one default per module
  • Imports are live read-only bindings, not copies
  • Modules run once, are cached, and are strict mode

2. Loading Rules

javascript
const { f, default: g } = await import('./m.js');

import() returns a promise; await gives the module namespace object

  • Static import only at the top level
  • Node: .mjs file or "type": "module"
  • Include the file extension: './m.js'

3. Map and Set

ObjectMap
Keysstring or symbolany type
Orderinteger keys first, then insertionpure insertion
SizeObject.keys(o).lengthmap.size
  • Map API: set get has delete size
  • Set keeps unique values; [...new Set(arr)] dedupes back to an array
SameValueZero

Map and Set treat NaN as equal to NaN, but two {} objects are different.

JavaScriptPage 6

Modern JS Cheat Sheet

1. Unpack and Combine

  • Rest goes last; defaults apply only to undefined
  • Spread is a shallow copy; later keys win
javascript
const { a, b = 1, ...rest } = obj
const [x, , z] = arr
const m = { ...a, ...b }
const all = [...a, ...b]
fn(...args)

2. Safe Access and Pipeline

javascript
user?.address?.city ?? 'N/A'
arr.filter(f).map(m).reduce(r, init)
  • ?? replaces only null/undefined; || any falsy
  • reduce: pass init, return acc

3. Modules and Collections

ExportImport
Defaultexport default ximport x from './m.js'
Namedexport { y }import { y } from './m.js'
Bothimport x, { y } from './m.js'
MapSet
Createnew Map([[k, v]])new Set(arr)
Usemap.get(k)set.has(v)
To array[...map][...set]
Remember

Named imports need exact names; default takes any. Object integer keys sort first; Map keeps pure insertion order.

JavaScriptPage 7

Check yourself

What does this print?
  • 10 0
  • || replaces any falsy value, ?? only null or undefined
const count = 0;
console.log(count || 10, count ?? 10);
What does ['1','2','3'].map(parseInt) return, and how do you fix it?
  • [1, NaN, NaN]: map passes the index as parseInt's radix
  • Fix: .map(Number)
With const user = {}, what does user?.address.city do?
  • Throws a TypeError: ?. guards only user, and address is undefined
  • Write user.address?.city