ES6+ Modern JavaScript
What is ES6?
ES6 (also called ES2015) was a massive update to JavaScript in 2015. Since then, new features are added yearly. These "modern JavaScript" features aren't optional — they're how production code is written today.
let and const
var is the old way to declare variables. It has quirks that cause bugs:JavaScript
// var is function-scoped, not block-scoped
if (true) {
var x = 10;
}
console.log(x); // 10 — leaked out of the if block!
// let and const are block-scoped
if (true) {
let y = 10;
const z = 20;
}
console.log(y); // ReferenceError — y is not definedRule: Use
const by default. Use let when you need to reassign. Never use var.Template literals
Backtick strings with embedded expressions:
JavaScript
const name = 'Alice';
const age = 28;
// Old way
const msg = 'Hello, ' + name + '! You are ' + age + ' years old.';
// Template literal
const msg = `Hello, ${name}! You are ${age} years old.`;They also support multi-line strings:
JavaScript
const html = `
<div class="card">
<h2>${title}</h2>
<p>${description}</p>
</div>
`;Arrow functions
A shorter function syntax:
JavaScript
// Traditional
function add(a, b) {
return a + b;
}
// Arrow function
const add = (a, b) => a + b;
// With a body
const greet = (name) => {
const message = `Hello, ${name}!`;
return message;
};
// Single parameter — parentheses optional
const double = n => n * 2;Arrow functions also don't have their own
this — they inherit it from the surrounding scope. This is important for callbacks and event handlers.Default parameters
JavaScript
function createUser(name, role = 'viewer', active = true) {
return { name, role, active };
}
createUser('Alice'); // { name: 'Alice', role: 'viewer', active: true }
createUser('Bob', 'admin'); // { name: 'Bob', role: 'admin', active: true }Rest and spread operators
Rest (
...) collects remaining arguments:JavaScript
function sum(...numbers) {
return numbers.reduce((total, n) => total + n, 0);
}
sum(1, 2, 3, 4); // 10Spread (
...) expands arrays and objects:JavaScript
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 }; // { a: 1, b: 2, c: 3 }Enhanced object literals
JavaScript
const name = 'Alice';
const age = 28;
// Old way
const user = { name: name, age: age };
// Shorthand — when key and variable name match
const user = { name, age };
// Computed property names
const field = 'email';
const user = { [field]: '[email protected]' };
// { email: '[email protected]' }
// Method shorthand
const calc = {
add(a, b) { return a + b; },
subtract(a, b) { return a - b; },
};Modules (import/export)
Split code into reusable files:
JavaScript
// utils.js
export function formatDate(date) {
return date.toLocaleDateString();
}
export const API_URL = 'https://api.example.com';
export default function fetchData(endpoint) {
return fetch(`${API_URL}/${endpoint}`).then(r => r.json());
}JavaScript
// app.js
import fetchData, { formatDate, API_URL } from './utils.js';export— named export (import with curly braces).export default— default export (import without curly braces, name it whatever you want).
Template literals recap
Template literals use backticks (`
`), not single or double quotes. They solve three problems at once: string interpolation, readable multi-line text, and tagged templates for advanced formatting.
Interpolation embeds any expression inside $ — variables, function calls, or ternaries: Total: $${
(price * qty).toFixed(2)}
Compare the old and new styles side by side:
. Multi-line strings no longer need awkward \n` concatenation — paste HTML snippets or SQL queries directly. For user-generated content in HTML, still escape or sanitize; template literals do not prevent XSS by themselves.Compare the old and new styles side by side:
JavaScript
const item = 'coffee';
const count = 2;
const line = 'Order: ' + count + 'x ' + item + ' — $' + (4.5 * count);
const lineModern = `Order: ${count}x ${item} — $${(4.5 * count).toFixed(2)}`;Reach for template literals any time a string mixes fixed text with dynamic values. Reserve
+ concatenation for the rare case of adding a single primitive to a string in a tight loop where micro-optimizations matter — in everyday code, readability wins.Modules in depth
ES modules split code into files that explicitly import and export dependencies. In the browser, use
<script type="module" src="app.js"> — module scripts are deferred by default and run in strict mode. In Node.js, use "type": "module" in package.json or the .mjs extension.Named exports let a file expose multiple symbols. Import them with matching names inside curly braces, or rename: `import
{
formatDate as fmt } from './utils.js'`. Default exports suit a single main thing per file — one React component, one router, one config object. A file can have one default export and many named exports together.
JavaScript
// math.js
export const PI = 3.14159;
export function square(n) { return n * n; }
export default function add(a, b) { return a + b; }
// main.js
import add, { PI, square } from './math.js';Re-export from a barrel file to simplify imports: `export
{
formatDate } from './format.js'
. Avoid default-export everything — named exports improve autocomplete and make refactors safer because symbol names stay consistent across files.
Module scope is private by default. Top-level const and function declarations are not global unless you attach them to window` deliberately. That encapsulation is a major reason modern codebases scale.Classes
JavaScript
class Animal {
constructor(name, sound) {
this.name = name;
this.sound = sound;
}
speak() {
return `${this.name} says ${this.sound}!`;
}
}
class Dog extends Animal {
constructor(name) {
super(name, 'woof');
}
fetch(item) {
return `${this.name} fetches the ${item}!`;
}
}
const rex = new Dog('Rex');
rex.speak(); // "Rex says woof!"
rex.fetch('ball'); // "Rex fetches the ball!"Classes are syntactic sugar over JavaScript's prototype-based inheritance — they don't introduce a new OOP model, just a cleaner syntax.
Map and Set
Map — like objects, but keys can be anything:
JavaScript
const cache = new Map();
cache.set('user:1', { name: 'Alice' });
cache.set('user:2', { name: 'Bob' });
cache.get('user:1'); // { name: 'Alice' }
cache.has('user:3'); // false
cache.size; // 2Set — a collection of unique values:
JavaScript
const tags = new Set(['html', 'css', 'html', 'javascript']);
console.log(tags); // Set { 'html', 'css', 'javascript' }
tags.add('react');
tags.has('html'); // true
tags.size; // 4Deduplicate an array:
JavaScript
const unique = [...new Set([1, 2, 2, 3, 3, 3])]; // [1, 2, 3]Destructuring in practice
Destructuring is not just syntax sugar — it documents the shape of data you expect. Function parameters benefit especially: `function render(
{
title, body, publishedAt })
makes required fields obvious. Combine with defaults: function connect({
host = 'localhost', port = 3000 } =
)
. For arrays, skip elements with commas: const[
, second] = list
grabs the second item only.
Key takeaway
Modern JavaScript is more readable, concise, and powerful than older versions. Use const/let instead of var`, arrow functions for callbacks, template literals for strings, destructuring for data extraction, and modules for code organization. These features are the baseline for any JavaScript job or project.