var, let, const ES2015 ☆ Variable declarations with different scoping and mutability rules.
var x = 1 ;
var x = 2 ;
let y = 1 ;
const z = [];
z.push( 1 );
Template Literals ES2015 ☆ String literals with embedded expressions and multi-line support.
const name = 'World' ;
const greeting = `Hello, ${name}!` ;
const html = `
<div>
<p>No more \n hacks</p>
</div>
`;
const price = 9.99 ;
const msg = `Total: $${(price * 1.1).toFixed(2)}` ;
function highlight(strings, ...values) {
return strings.reduce((acc, str, i) =>
acc + str + (values[i] ? `<b>${values[i]}</b>` : '' ), '' );
}
const result = highlight `Price is ${price} USD` ;
Arrow Functions ES2015 ☆ Concise function syntax that lexically binds `this` from the enclosing scope.
function add(a, b) { return a + b; }
const add = (a, b) => a + b;
const greet = (name) => {
const msg = `Hello, ${name}!` ;
return msg;
};
class Timer {
start() {
setTimeout(() => {
this .tick();
}, 1000 );
}
}
Array Methods ☆ Functional array transformations: map, filter, reduce, find, and more.
const nums = [ 1 , 2 , 3 , 4 , 5 ];
nums.map(n => n * 2 );
nums.filter(n => n % 2 === 0 );
nums.reduce((sum, n) => sum + n, 0 );
nums.find(n => n > 3 );
nums.findIndex(n => n > 3 );
nums.some(n => n > 4 );
nums.every(n => n > 0 );
[[ 1 , 2 ], [ 3 , 4 ]].flat();
nums.flatMap(n => [n, n * 2 ]);
Array. from ({ length: 3 }, (_, i) => i);
Destructuring ES2015 ☆ Unpack values from arrays or properties from objects into distinct variables.
const [a, b, ...rest] = [ 1 , 2 , 3 , 4 , 5 ];
const { name, age, city = 'Unknown' } = { name: 'Alice' , age: 30 };
const { name: userName } = { name: 'Bob' };
const { address: { street } } = { address: { street: '123 Main St' } };
function display({ title, author = 'Anonymous' }) {
return `${title} by ${author}` ;
}
Spread & Rest ES2015 ☆ Spread expands iterables; rest collects remaining arguments into an array.
const a = [ 1 , 2 ];
const b = [...a, 3 , 4 ];
const defaults = { color: 'blue' , size: 'md' };
const custom = { ...defaults, size: 'lg' };
Math.max(...[ 1 , 5 , 3 ]);
function sum(...nums) {
return nums.reduce((acc, n) => acc + n, 0 );
}
sum( 1 , 2 , 3 , 4 );
const [head, ...tail] = [ 1 , 2 , 3 , 4 ];
Hoisting ES2015 ☆ Declarations are moved to the top of their scope at compile time. var is hoisted and initialized to undefined; let/const are hoisted but stay in the Temporal Dead Zone until their declaration line.
console.log(x);
var x = 5 ;
console.log(x);
console.log(y);
let y = 10 ;
greet();
function greet() { console.log( "Hello!" ); }
sayHi();
var sayHi = () => console.log( "Hi!" );
Error Handling ☆ try/catch/finally patterns and custom error types.
try {
const data = JSON.parse(rawInput);
processData(data);
} catch (err) {
console.error(err.message);
} finally {
cleanup();
}
class ValidationError extends Error {
constructor(field, message) {
super (message);
this .name = 'ValidationError' ;
this .field = field;
}
}
try {
validate(input);
} catch (err) {
if (err instanceof ValidationError) {
showFieldError(err.field, err.message);
} else if (err instanceof NetworkError) {
retry();
} else {
throw err;
}
}
throw new Error( 'Failed to load' , { cause: originalError });
Execution Context & Call Stack ☆ Every function call creates an Execution Context — the environment in which code runs.
function outer() {
let x = 10 ;
function inner() {
let y = 20 ;
console.log(x + y);
}
inner();
}
outer();
Classes ES2015 ☆ Syntactic sugar over prototypal inheritance for defining object blueprints.
class Animal {
#name;
constructor(name) {
this .#name = name;
}
speak() {
return `${this.#name} makes a noise.` ;
}
get name() { return this .#name; }
static create(name) { return new Animal(name); }
}
class Dog extends Animal {
constructor(name) {
super (name);
}
speak() {
return `${this.name} barks.` ;
}
}
const d = new Dog( 'Rex' );
d.speak();
d instanceof Animal;
ES Modules ES2015 ☆ Native JavaScript module system with static import/export syntax.
export const PI = 3.14 ;
export function add(a, b) { return a + b; }
export class Vector { ... }
export default function main() { ... }
import { PI, add } from './math.js' ;
import main from './app.js' ;
import { add as sum } from './math.js' ;
import * as math from './math.js' ;
math.PI; math.add( 1 , 2 );
export { add } from './math.js' ;
export * from './utils.js' ;
const { add } = await import ( './math.js' );
Promises ES2015 ☆ Objects representing the eventual completion or failure of an asynchronous operation.
const p = new Promise((resolve, reject) => {
setTimeout(() => resolve( 'done' ), 1000 );
});
fetch( '/api/data' )
.then(res => res.json())
.then(data => process(data))
. catch (err => console.error(err))
. finally (() => setLoading( false ));
Promise.all([p1, p2, p3]);
Promise.allSettled([p1, p2, p3]);
Promise.race([p1, p2]);
Promise.any([p1, p2, p3]);
const results = await Promise.allSettled([p1, p2]);
results.forEach(r => {
if (r.status === 'fulfilled' ) console.log(r.value);
else console.error(r.reason);
});
async / await ES2017 ☆ Syntactic sugar over Promises for writing asynchronous code in a synchronous style.
async function fetchUser(id) {
const res = await fetch( `/api/users/${id}` );
const data = await res.json();
return data;
}
async function fetchSafe(url) {
try {
const res = await fetch(url);
if (!res.ok) throw new Error( `HTTP ${res.status}` );
return await res.json();
} catch (err) {
console.error( 'Fetch failed:' , err.message);
return null ;
}
}
async function loadAll(ids) {
const promises = ids.map(id => fetchUser(id));
return Promise.all(promises);
}
fetch & AbortController ES2015 ☆ Native browser API for HTTP requests with cancellation support.
const res = await fetch( '/api/users' );
const users = await res.json();
const res = await fetch( '/api/users' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON.stringify({ name: 'Alice' }),
});
if (!res.ok) throw new Error( `HTTP ${res.status}` );
const controller = new AbortController();
const { signal } = controller;
fetch( '/api/data' , { signal })
.then(r => r.json())
. catch (err => {
if (err.name === 'AbortError' ) return ;
throw err;
});
controller.abort();
const timeout = setTimeout(() => controller.abort(), 5000 );
Optional Chaining (?.) ES2020 ☆ Safely access deeply nested properties without explicit null checks.
const user = { address: { city: 'NYC' } };
const city = user && user.address && user.address.city;
const city = user?.address?.city;
const len = str?.length;
const upper = str?.toUpperCase();
const first = arr?.[ 0 ];
const result = callback?.();
const city = user?.address?.city ?? 'Unknown' ;
Nullish Coalescing (??) ES2020 ☆ Returns the right-hand value only when the left is null or undefined.
const count = 0 || 10 ;
const count = 0 ?? 10 ;
const name = '' ?? 'Anonymous' ;
function getConfig(userConfig) {
return {
timeout: userConfig.timeout ?? 3000 ,
retries: userConfig.retries ?? 3 ,
debug: userConfig.debug ?? false ,
};
}
let x = null ;
x ??= 'default' ;
Logical Assignment Operators ES2021 ☆ Combine logical operators with assignment for concise conditional mutation.
let config = null ;
config ??= { theme: 'dark' };
let active = false ;
active ??= true ;
let name = '' ;
name ||= 'Anonymous' ;
let count = 0 ;
count ||= 1 ;
let user = { name: 'Alice' };
user &&= { ...user, loggedIn: true };
let guest = null ;
guest &&= { loggedIn: true };
cache[key] ??= expensiveComputation(key);
Object Methods ☆ Static methods on Object for transforming and inspecting object data.
const user = { name: 'Alice' , age: 30 , role: 'admin' };
Object.keys(user);
Object.values(user);
Object.entries(user);
const filtered = Object.fromEntries(
Object.entries(user).filter(([, v]) => typeof v === 'string' )
);
const clone = Object.assign({}, user);
const merged = Object.assign({}, defaults, overrides);
Object.freeze(user);
Object.defineProperty(user, 'id' , {
value: 42 ,
writable: false ,
enumerable: false ,
});
Set & Map ES2015 ☆ Built-in collection types for unique values (Set) and key-value pairs (Map).
const s = new Set([ 1 , 2 , 2 , 3 ]);
s.add( 4 );
s.has( 2 );
s. delete ( 1 );
s.size;
[...s];
const unique = [... new Set(arr)];
const m = new Map();
m.set( 'a' , 1 );
m.set({ id: 1 }, 'object key' );
m.get( 'a' );
m.has( 'a' );
m.size;
for ( const [key, value] of m) { ... }
m.forEach((value, key) => { ... });
Object.fromEntries(m);
new Map(Object.entries(obj));
Debounce & Throttle ☆ Rate-limiting patterns: debounce delays until idle, throttle limits to one call per window.
function debounce(fn, delay) {
let timerId;
return function (...args) {
clearTimeout(timerId);
timerId = setTimeout(() => fn.apply( this , args), delay);
};
}
const onSearch = debounce((query) => fetchResults(query), 300 );
input.addEventListener( 'input' , (e) => onSearch(e.target.value));
function throttle(fn, limit) {
let lastRan = 0 ;
return function (...args) {
const now = Date.now();
if (now - lastRan >= limit) {
lastRan = now;
fn.apply( this , args);
}
};
}
window.addEventListener( 'scroll' , throttle(updateProgressBar, 100 ));
function throttleLeading(fn, limit) {
let locked = false ;
return function (...args) {
if (!locked) {
fn.apply( this , args);
locked = true ;
setTimeout(() => (locked = false ), limit);
}
};
}
Memoization ☆ Cache the result of a function call keyed by its arguments to avoid redundant computation.
function memoize(fn) {
const cache = new Map();
return function (...args) {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = fn.apply( this , args);
cache.set(key, result);
return result;
};
}
const expensiveCalc = memoize((n) => {
return n * n;
});
expensiveCalc( 42 );
expensiveCalc( 42 );
function memoizeByRef(fn) {
const cache = new WeakMap();
return function (obj) {
if (cache.has(obj)) return cache.get(obj);
const result = fn(obj);
cache.set(obj, result);
return result;
};
}
let lastDeps, lastResult;
function useMemoShim(factory, deps) {
if (!lastDeps || deps.some((d, i) => d !== lastDeps[i])) {
lastResult = factory();
lastDeps = deps;
}
return lastResult;
}
Generators ES2015 ☆ Functions that can pause and resume execution, producing a sequence of values on demand.
function * counter(start = 0 ) {
while ( true ) {
yield start++;
}
}
const gen = counter( 5 );
gen.next();
gen.next();
function * range(start, end, step = 1 ) {
for ( let i = start; i < end; i += step) {
yield i;
}
}
[...range( 0 , 6 , 2 )];
function * entries(obj) {
for ( const key of Object.keys(obj)) {
yield [key, obj[key]];
}
}
async function * paginate(url) {
let page = 1 ;
while ( true ) {
const data = await fetch( `${url}?page=${page++}` ).then(r => r.json());
if (!data.length) return ;
yield data;
}
}
Symbol ES2015 ☆ Unique, immutable primitive values used as object property keys.
const s1 = Symbol( 'id' );
const s2 = Symbol( 'id' );
s1 === s2;
const ID = Symbol( 'id' );
const obj = { [ID]: 42 , name: 'Alice' };
obj[ID];
Object.keys(obj);
class Range {
constructor(start, end) {
this .start = start;
this .end = end;
}
[Symbol.iterator]() {
let current = this .start;
const end = this .end;
return {
next() {
return current <= end
? { value: current++, done: false }
: { done: true };
},
};
}
}
[... new Range( 1 , 5 )];
Proxy & Reflect ES2015 ☆ Intercept and redefine fundamental operations on objects.
const validator = {
set(target, prop, value) {
if (prop === 'age' && typeof value !== 'number' ) {
throw new TypeError( 'Age must be a number' );
}
return Reflect.set(target, prop, value);
},
};
const person = new Proxy({}, validator);
person.age = 25 ;
person.age = '25' ;
function createLogged(target) {
return new Proxy(target, {
get(obj, prop) {
console.log( `Getting ${prop}` );
return Reflect.get(obj, prop);
},
});
}
const withDefaults = new Proxy({}, {
get(obj, prop) {
return prop in obj ? obj[prop] : `<${prop}>` ;
},
});