DEV Community

楊東霖
楊東霖

Posted on • Originally published at devtoolkit.cc

JavaScript ES6+ Features Every Developer Should Know

ES6 (ECMAScript 2015) was the biggest update to JavaScript in the language's history. Combined with the improvements that followed in ES2017 through ES2024, modern JavaScript is a much more expressive and powerful language than it was a decade ago. This guide covers the features you'll use every day, with practical examples and the "why" behind each one.

Arrow Functions

Arrow functions provide a concise syntax and, importantly, don't have their own this binding — they inherit this from the surrounding scope.

// Traditional function
const add = function(a, b) { return a + b; };

// Arrow function — same thing, shorter
const add = (a, b) => a + b;

// Single parameter — parens optional
const double = n => n * 2;

// No parameters — parens required
const getTimestamp = () => Date.now();

// Multi-line body — needs curly braces and explicit return
const processUser = (user) => {
  const fullName = `${user.first} ${user.last}`;
  return { ...user, fullName };
};

// Returning an object literal — wrap in parens
const makePoint = (x, y) => ({ x, y });

// The this binding difference
class Timer {
  constructor() {
    this.count = 0;
  }

  start() {
    // Arrow function: 'this' is the Timer instance
    setInterval(() => {
      this.count++;
      console.log(this.count);
    }, 1000);

    // Regular function would break: 'this' would be undefined (strict mode)
  }
}
Enter fullscreen mode Exit fullscreen mode

Destructuring

Destructuring lets you unpack values from arrays and objects into distinct variables.

Array Destructuring

const [first, second, third] = [10, 20, 30];
console.log(first); // 10

// Skip elements with commas
const [,, third] = [1, 2, 3];
console.log(third); // 3

// Default values
const [a = 0, b = 0, c = 0] = [1, 2];
console.log(c); // 0

// Swap variables without a temp
let x = 1, y = 2;
[x, y] = [y, x];
console.log(x, y); // 2 1

// Rest element
const [head, ...tail] = [1, 2, 3, 4, 5];
console.log(head); // 1
console.log(tail); // [2, 3, 4, 5]
Enter fullscreen mode Exit fullscreen mode

Object Destructuring

const user = { id: 1, name: 'Alice', age: 30, role: 'admin' };

const { name, age } = user;
console.log(name); // 'Alice'

// Rename while destructuring
const { name: fullName, role: userRole } = user;
console.log(fullName); // 'Alice'

// Default values
const { name, city = 'Unknown' } = user;
console.log(city); // 'Unknown'

// Nested destructuring
const { address: { street, zip } = {} } = user;

// Rest properties
const { id, ...rest } = user;
console.log(rest); // { name: 'Alice', age: 30, role: 'admin' }

// In function parameters — very common pattern
function displayUser({ name, role, age = 0 }) {
  console.log(`${name} (${role}), age ${age}`);
}
displayUser(user);

// Destructuring API responses
async function loadUser(id) {
  const { data: { user: { name, email } } } = await fetchUser(id);
  return { name, email };
}
Enter fullscreen mode Exit fullscreen mode

Template Literals

const name = 'World';
const greeting = `Hello, ${name}!`;

// Multi-line strings
const html = `


    ## ${user.name}
    ${user.bio}



`;

// Any expression works inside ${}
const price = 9.99;
const tax = 0.08;
const total = `Total: $${(price * (1 + tax)).toFixed(2)}`;

// Tagged templates (advanced)
function highlight(strings, ...values) {
  return strings.reduce((result, str, i) => {
    const val = values[i] !== undefined ? `<mark>${values[i]}</mark>` : '';
    return result + str + val;
  }, '');
}

const name = 'Alice';
const msg = highlight`Welcome back, ${name}! You have ${5} messages.`;
// 'Welcome back, <mark>Alice</mark>! You have <mark>5</mark> messages.'
Enter fullscreen mode Exit fullscreen mode

Spread and Rest Operators

// Rest: collect multiple arguments into an array
function sum(...numbers) {
  return numbers.reduce((total, n) => total + n, 0);
}
sum(1, 2, 3, 4, 5); // 15

// Spread: expand an array/object into individual values

// Combine arrays
const a = [1, 2, 3];
const b = [4, 5, 6];
const combined = [...a, ...b]; // [1, 2, 3, 4, 5, 6]

// Copy an array
const copy = [...a];

// Spread into function arguments
Math.max(...numbers);

// Merge objects
const defaults = { theme: 'light', lang: 'en', debug: false };
const userPrefs = { theme: 'dark', lang: 'fr' };
const config = { ...defaults, ...userPrefs };
// { theme: 'dark', lang: 'fr', debug: false }

// Add or override a property immutably
const updated = { ...user, name: 'New Name', updatedAt: new Date() };

// Clone with spread (shallow)
const clone = { ...original };
Enter fullscreen mode Exit fullscreen mode

let and const

// var: function-scoped, hoisted (avoid in modern code)
var x = 1;

// let: block-scoped, reassignable
let count = 0;
count++;

// const: block-scoped, cannot be reassigned (but objects/arrays can be mutated)
const PI = 3.14159;
const user = { name: 'Alice' };
user.name = 'Bob';       // ✅ OK — mutating the object
user = { name: 'Carol' } // ❌ TypeError — reassigning the binding

// Use const by default, let when you need to reassign, never var
Enter fullscreen mode Exit fullscreen mode

Modules (import/export)

// math.js — named exports
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export function multiply(a, b) { return a * b; }

// Rename on export
export { add as sum };

// Default export (one per file)
export default function divide(a, b) { return a / b; }

// app.js — importing
import divide from './math.js';           // default import
import { add, PI } from './math.js';      // named imports
import { add as plus } from './math.js';  // rename on import
import * as math from './math.js';        // import everything

// Re-export (barrel files)
// index.js
export { add, multiply } from './math.js';
export { default as divide } from './math.js';
Enter fullscreen mode Exit fullscreen mode

Classes

class Animal {
  #name;  // private field (ES2022)

  constructor(name, sound) {
    this.#name = name;
    this.sound = sound;
  }

  get name() { return this.#name; }

  speak() {
    return `${this.#name} says ${this.sound}`;
  }

  static create(name, sound) {
    return new Animal(name, sound);
  }
}

class Dog extends Animal {
  constructor(name) {
    super(name, 'woof');
    this.tricks = [];
  }

  learn(trick) {
    this.tricks.push(trick);
    return this;  // enable chaining
  }

  speak() {
    const base = super.speak();
    return `${base}! It knows: ${this.tricks.join(', ')}`;
  }
}

const dog = new Dog('Rex');
dog.learn('sit').learn('shake');
console.log(dog.speak());
// 'Rex says woof! It knows: sit, shake'
Enter fullscreen mode Exit fullscreen mode

Optional Chaining and Nullish Coalescing

// Optional chaining (?.) — ES2020
const user = null;

// Without optional chaining — throws TypeError
// const city = user.address.city;

// With optional chaining — returns undefined safely
const city = user?.address?.city;

// Works with methods
const result = obj?.method?.();

// Works with arrays/bracket notation
const firstTag = post?.tags?.[0];

// Nullish coalescing (??) — ES2020
// Returns right side only when left is null or undefined (not 0 or '')
const name = user?.name ?? 'Anonymous';
const port = config.port ?? 3000;

// vs logical OR (||) which also triggers on 0, '', false
const port1 = config.port ?? 3000;  // 0 stays 0
const port2 = config.port || 3000;  // 0 becomes 3000 — bug!

// Nullish coalescing assignment (??=) — ES2021
user.preferences ??= {};   // assign only if null/undefined
user.score ||= 0;          // assign if falsy (||=)
user.count &&= user.count + 1; // assign only if truthy (&&=)
Enter fullscreen mode Exit fullscreen mode

Promises and Async/Await

// Covered in detail in the Promises guide
// Key syntax reminder:
async function fetchData(url) {
  try {
    const response = await fetch(url);
    return await response.json();
  } catch (error) {
    console.error('Failed:', error);
    throw error;
  }
}
Enter fullscreen mode Exit fullscreen mode

Map and Set

// Set: collection of unique values
const set = new Set([1, 2, 3, 2, 1]);
console.log(set.size); // 3
set.add(4);
set.has(2); // true
set.delete(2);
[...set]; // [1, 3, 4]

// Remove duplicates from an array
const unique = [...new Set([1, 1, 2, 3, 3])]; // [1, 2, 3]

// Map: key-value pairs with any key type
const map = new Map();
const objKey = { id: 1 };
map.set(objKey, 'some value');
map.set('name', 'Alice');
map.get(objKey); // 'some value'
map.size; // 2
map.has('name'); // true

// Iterate
for (const [key, value] of map) {
  console.log(key, value);
}

// Convert object to Map
const obj = { a: 1, b: 2, c: 3 };
const mapFromObj = new Map(Object.entries(obj));

// Convert Map back to object
const objFromMap = Object.fromEntries(map);
Enter fullscreen mode Exit fullscreen mode

Symbol, WeakMap, WeakSet, WeakRef

// Symbol: unique, immutable primitive
const sym = Symbol('description');
const sym2 = Symbol('description');
sym === sym2; // false — always unique

// Use as object keys to avoid collisions
const ID = Symbol('id');
const obj = { [ID]: 123, name: 'Alice' };
obj[ID]; // 123

// Well-known symbols
class MyArray {
  [Symbol.iterator]() { /* custom iteration */ }
}

// WeakMap: keys must be objects; entries can be garbage collected
const cache = new WeakMap();
function getResult(obj) {
  if (cache.has(obj)) return cache.get(obj);
  const result = expensiveCalc(obj);
  cache.set(obj, result);
  return result;
}
Enter fullscreen mode Exit fullscreen mode

Logical Assignment and Other ES2021+ Features

// Logical assignment (ES2021)
a ||= b;   // a = a || b
a &&= b;   // a = a && b
a ??= b;   // a = a ?? b

// Numeric separators (ES2021) — improve readability
const million = 1_000_000;
const hex     = 0xFF_EC_D0;
const bytes   = 0b1010_0001;

// Object.hasOwn() (ES2022) — safer than hasOwnProperty
Object.hasOwn(obj, 'key'); // true if own property

// Array.at() (ES2022) — supports negative indices
const arr = [1, 2, 3, 4, 5];
arr.at(-1);  // 5 (last element)
arr.at(-2);  // 4

// String.at() works the same way
'hello'.at(-1); // 'o'

// structuredClone() (ES2022) — deep clone
const original = { a: 1, b: { c: 2 } };
const deep = structuredClone(original);
deep.b.c = 99;
console.log(original.b.c); // 2 — not affected

// Error cause (ES2022)
try {
  await connectToDatabase();
} catch (err) {
  throw new Error('Failed to load user', { cause: err });
}
Enter fullscreen mode Exit fullscreen mode

Quick Reference

// Variables
const x = 1;      // block-scoped, no reassignment
let y = 2;        // block-scoped, reassignable

// Functions
const fn = (a, b) => a + b;       // arrow function
const fn = async () => {};         // async arrow
function fn(...args) {}            // rest params

// Strings
`Hello ${name}`                    // template literal

// Destructuring
const { a, b } = obj;             // object
const [x, y] = arr;               // array
function fn({ a, b = 0 } = {}) {} // default params

// Spread/Rest
{ ...obj, key: val }               // merge/add
[...arr1, ...arr2]                 // combine arrays
fn(...arr)                         // spread as args

// Modules
import def from './mod'            // default
import { a, b } from './mod'       // named
export default fn                  // default export
export { a, b }                    // named exports

// Safe access
obj?.prop?.method?.()             // optional chaining
val ?? defaultVal                  // nullish coalescing

// Collections
new Set([1,2,3])                   // unique values
new Map([[key, val]])              // any-type keys
Enter fullscreen mode Exit fullscreen mode

Modern JavaScript is a joy to write when you know these features. Start incorporating them gradually — const/let, template literals, and arrow functions first, then destructuring and spread, then modules and classes. Within a few weeks, these patterns will feel completely natural.

Free Developer Tools

If you found this article helpful, check out DevToolkit — 40+ free browser-based developer tools with no signup required.

Popular tools: JSON Formatter · Regex Tester · JWT Decoder · Base64 Encoder

🛒 Get the DevToolkit Starter Kit on Gumroad — source code, deployment guide, and customization templates.

Top comments (0)