Combine modern JavaScript features into practical patterns — short-circuit assignment, object tricks, immutable updates, and more.
JavaScript's logical operators can be used for concise conditional patterns beyond simple boolean logic.
Default values with ||:
const name = userInput || 'Anonymous';
// Returns userInput if truthy, otherwise 'Anonymous'Nullish default with ??:
const count = data.count ?? 0;
// Only falls back to 0 if count is null/undefined
// Preserves 0, '', false (unlike ||)Guard with &&:
isLoggedIn && showDashboard();
// Only calls showDashboard() if isLoggedIn is truthy
const name = user && user.name;
// Returns user.name if user is truthy, otherwise user (null/undefined)Logical assignment operators (ES2021):
let config = {};
config.theme ??= 'light'; // assign if null/undefined
config.debug ||= false; // assign if falsy
config.retries &&= config.retries - 1; // assign if truthyConverting to boolean:
const hasItems = !!items.length; // 0 → false, 5 → true
const isValid = !!input.trim(); // '' → false, 'hello' → trueModern JavaScript provides elegant shortcuts for working with objects.
Shorthand properties — when variable name matches key:
const name = 'Alice';
const age = 30;
// Instead of { name: name, age: age }
const user = { name, age };Computed property names:
const field = 'email';
const obj = { [field]: 'alice@example.com' };
console.log(obj.email); // 'alice@example.com'
// Dynamic keys
const prefix = 'user';
const data = {
[`${prefix}Name`]: 'Alice',
[`${prefix}Age`]: 30,
};Object.assign() vs spread:
// Both merge objects (spread is preferred)
const merged1 = Object.assign({}, defaults, overrides);
const merged2 = { ...defaults, ...overrides };Object.freeze() — prevent modifications:
const config = Object.freeze({ port: 3000, host: 'localhost' });
config.port = 8080; // silently fails (throws in strict mode)Object.keys/values/entries:
const user = { name: 'Alice', age: 30 };
Object.keys(user); // ['name', 'age']
Object.values(user); // ['Alice', 30]
Object.entries(user); // [['name', 'Alice'], ['age', 30]]In modern JavaScript — especially with React and Redux — you should never mutate state directly. Instead, create new copies with the changes applied.
Updating objects:
const user = { name: 'Alice', age: 25, city: 'Paris' };
// Create new object with updated age
const updated = { ...user, age: 26 };
console.log(user.age); // 25 (original unchanged)
console.log(updated.age); // 26Adding items to arrays:
const items = ['apple', 'banana'];
const added = [...items, 'cherry'];
// ['apple', 'banana', 'cherry']
const prepended = ['mango', ...items];
// ['mango', 'apple', 'banana']Removing items from arrays:
const numbers = [1, 2, 3, 4, 5];
const without3 = numbers.filter(n => n !== 3);
// [1, 2, 4, 5]Updating items in arrays:
const todos = [
{ id: 1, text: 'Buy milk', done: false },
{ id: 2, text: 'Clean house', done: false },
];
const toggled = todos.map(todo =>
todo.id === 1 ? { ...todo, done: true } : todo
);Updating nested objects:
const state = { user: { name: 'Alice', address: { city: 'Paris' } } };
const newState = {
...state,
user: {
...state.user,
address: {
...state.user.address,
city: 'London',
},
},
};Functional programming concepts are widely used in modern JavaScript.
Pure functions — no side effects, same input always gives same output:
// Pure
const add = (a, b) => a + b;
const toUpper = str => str.toUpperCase();
// Impure (modifies external state)
let count = 0;
const increment = () => ++count;Higher-order functions — functions that accept or return functions:
// Accepts a function
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2);
// Returns a function
const multiplier = factor => number => number * factor;
const double = multiplier(2);
const triple = multiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15Composition — combining functions:
const pipe = (...fns) => value =>
fns.reduce((acc, fn) => fn(acc), value);
const processName = pipe(
str => str.trim(),
str => str.toLowerCase(),
str => str.replace(/\s+/g, '-')
);
console.log(processName(' Hello World ')); // 'hello-world'IIFE (Immediately Invoked Function Expression) — for one-time initialization:
const config = (() => {
const env = 'production';
return { env, debug: env !== 'production' };
})();Recent JavaScript versions added several quality-of-life features.
Numeric separators for readability:
const billion = 1_000_000_000;
const bytes = 0xFF_FF_FF;
const fraction = 0.000_001;globalThis — universal global object:
// Works in browsers, Node.js, web workers, etc.
globalThis.myGlobal = 'hello';structuredClone() — proper deep copy:
const original = { a: 1, nested: { b: 2 } };
const deep = structuredClone(original);
deep.nested.b = 99;
console.log(original.nested.b); // 2 (unaffected!)Array.at() — access from the end:
const arr = ['a', 'b', 'c', 'd'];
console.log(arr.at(-1)); // 'd' (last element)
console.log(arr.at(-2)); // 'c' (second to last)Object.hasOwn() — safer than hasOwnProperty:
const obj = { name: 'Alice' };
console.log(Object.hasOwn(obj, 'name')); // true
console.log(Object.hasOwn(obj, 'toString')); // falseString replaceAll():
const text = 'foo-bar-baz';
console.log(text.replaceAll('-', '_')); // 'foo_bar_baz'<div id="output"></div>
<script>
// Immutable update
const user = { name: 'Alice', age: 25, city: 'Paris' };
const updated = { ...user, age: 26 };
// Short-circuit default
const displayName = user.nickname ?? user.name;
// Shorthand properties
const x = 10, y = 20;
const point = { x, y };
// Deep clone with structuredClone
const original = { data: { items: [1, 2, 3] } };
const cloned = structuredClone(original);
cloned.data.items.push(4);
// Array.at() for last element
const colors = ['red', 'green', 'blue'];
const lastColor = colors.at(-1);
const output = document.getElementById('output');
output.innerHTML = `
<p>Original age: ${user.age}, Updated age: ${updated.age}</p>
<p>Display name: ${displayName}</p>
<p>Point: {x: ${point.x}, y: ${point.y}}</p>
<p>Original items: [${original.data.items}] (not mutated)</p>
<p>Cloned items: [${cloned.data.items}]</p>
<p>Last color: ${lastColor}</p>
`;
</script>What does `{ ...user, age: 30 }` do?