Handbooks / JavaScript / Chapter 5
Modern JavaScript Features
7 pages · ~5 min✓ Reviewed
Builds on Event Loop and Async.
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;
| Spread | Rest | |
|---|---|---|
| Direction | expands out | collects in |
| Takes | iterable or object | remaining items |
| Gives | separate elements | one 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.
Destructuring, Spread and Rest in Practice
1. Rename, Default, Nest
{ id: userId }renames the key touserIdrole = 'guest'applies only when the value is undefinednull,0and''keep their value, no default- Nested
{ address: { city } }throws ifaddressis undefined
javascript
const { id: userId, role = 'guest' } = user; const { address: { city } } = user;
2. Rest and Spread
| Rest | Spread | |
|---|---|---|
| Does | collects the remaining | expands into elements |
| Position | last only | anywhere |
| Example | [first, ...others] | [...a, ...b] |
const { a, ...remaining } = objcollects 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.
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.cthrows ifbis undefined
| || | ?? | |
|---|---|---|
| Replaces | every falsy value (0, '', false) | only null, undefined |
count = 0 | gives 10 | keeps 0 |
a ?? b || cis a SyntaxError; add parenthesesx ??= vassigns only ifxis 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.cthrow??.guards only its left side. - Result of
0 ?? 10? 0;||gives 10. - Tagged vs plain
${}? The tag gets raw values; plain converts to strings.
Array Methods: map, filter, reduce
1. What each one does
| Method | Returns | Callback |
|---|---|---|
map | new array, same length | transforms each item |
filter | new array, maybe shorter | keeps items when truthy |
reduce | one 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] indexis passed toparseIntas 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 array | Methods |
|---|---|
| Untouched | map, filter, reduce |
| Mutated | sort, push, splice, reverse |
maponly for side effects: useforEachreducecallback that forgets to returnacc
reduce rule
Pass an initial value and return the accumulator every step.
ES Modules and Map and Set
1. Exports and Imports
export const f = 1pairs withimport { 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
importonly at the top level - Node:
.mjsfile or"type": "module" - Include the file extension:
'./m.js'
3. Map and Set
| Object | Map | |
|---|---|---|
| Keys | string or symbol | any type |
| Order | integer keys first, then insertion | pure insertion |
| Size | Object.keys(o).length | map.size |
- Map API:
setgethasdeletesize - 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.
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
| Export | Import | |
|---|---|---|
| Default | export default x | import x from './m.js' |
| Named | export { y } | import { y } from './m.js' |
| Both | import x, { y } from './m.js' |
| Map | Set | |
|---|---|---|
| Create | new Map([[k, v]]) | new Set(arr) |
| Use | map.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.
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 onlyuser, andaddressis undefined - Write
user.address?.city