Modern JavaScript ES6+ Features
ES6 (ES2015) and later versions introduced significant improvements to JavaScript. Understanding these features is essential for modern JavaScript development.
Let, Const, and Block Scope
// var - function scoped, hoisted
var x = 1;
if (true) {
var x = 2; // Same variable
console.log(x); // 2
}
console.log(x); // 2
// let - block scoped, not hoisted
let y = 1;
if (true) {
let y = 2; // Different variable
console.log(y); // 2
}
console.log(y); // 1
// const - block scoped, cannot be reassigned
const z = 1;
// z = 2; // Error!
// const with objects/arrays - reference is constant, not content
const user = { name: 'John' };
user.name = 'Jane'; // ✅ OK - modifying property
user.age = 30; // ✅ OK - adding property
// user = {}; // ❌ Error - cannot reassign
const numbers = [1, 2, 3];
numbers.push(4); // ✅ OK - modifying array
// numbers = []; // ❌ Error - cannot reassignArrow Functions
// Traditional function
function add(a, b) {
return a + b;
}
// Arrow function
const add = (a, b) => a + b;
// Single parameter - parentheses optional
const square = x => x * x;
// No parameters - parentheses required
const greet = () => console.log('Hello');
// Multiple statements - need braces and return
const calculate = (a, b) => {
const sum = a + b;
const product = a * b;
return { sum, product };
};
// Lexical 'this' binding
function Person() {
this.age = 0;
// Traditional function - 'this' refers to global object
setInterval(function() {
this.age++; // Won't work as expected
}, 1000);
// Arrow function - 'this' refers to Person
setInterval(() => {
this.age++; // ✅ Works correctly
}, 1000);
}
// Array methods with arrows
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
const evens = numbers.filter(n => n % 2 === 0);
const sum = numbers.reduce((acc, n) => acc + n, 0);
const hasThree = numbers.some(n => n === 3);
const allPositive = numbers.every(n => n > 0);Destructuring
// Array destructuring
const [first, second, third] = [1, 2, 3];
console.log(first); // 1
// Skip elements
const [a, , c] = [1, 2, 3];
console.log(a, c); // 1, 3
// Rest operator
const [head, ...tail] = [1, 2, 3, 4, 5];
console.log(head); // 1
console.log(tail); // [2, 3, 4, 5]
// Default values
const [x = 0, y = 0] = [10];
console.log(x, y); // 10, 0
// Object destructuring
const user = { name: 'John', age: 30, email: 'john@example.com' };
const { name, age } = user;
console.log(name, age); // 'John', 30
// Rename variables
const { name: userName, age: userAge } = user;
console.log(userName); // 'John'
// Default values
const { name, age, country = 'USA' } = user;
console.log(country); // 'USA'
// Nested destructuring
const data = {
user: {
name: 'John',
address: {
city: 'NYC',
zip: '10001'
}
}
};
const { user: { name, address: { city } } } = data;
console.log(name, city); // 'John', 'NYC'
// Function parameter destructuring
function greet({ name, age }) {
console.log(`Hello ${name}, you are ${age}`);
}
greet(user); // Hello John, you are 30Spread & Rest Operators
// Spread operator - expands iterables
// Arrays
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2]; // [1,2,3,4,5,6]
// Clone array
const original = [1, 2, 3];
const copy = [...original];
// Add to array
const withExtra = [...arr1, 4, 5];
// Objects
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const merged = { ...obj1, ...obj2 }; // { a: 1, b: 2, c: 3, d: 4 }
// Clone object
const person = { name: 'John', age: 30 };
const clone = { ...person };
// Override properties
const updated = { ...person, age: 31 };
// Rest operator - collects arguments
function sum(...numbers) {
return numbers.reduce((acc, n) => acc + n, 0);
}
console.log(sum(1, 2, 3, 4)); // 10
// With other parameters
function multiply(multiplier, ...numbers) {
return numbers.map(n => n * multiplier);
}
console.log(multiply(2, 1, 2, 3)); // [2, 4, 6]Template Literals
// String interpolation
const name = 'John';
const age = 30;
const message = `Hello, ${name}! You are ${age} years old.`;
// Multiline strings
const html = `
<div>
<h1>${name}</h1>
<p>Age: ${age}</p>
</div>
`;
// Expressions in templates
const result = `Sum: ${2 + 3}`;
const price = 19.99;
const tax = `Total: $${(price * 1.1).toFixed(2)}`;
// Tagged templates
function highlight(strings, ...values) {
return strings.reduce((result, str, i) => {
return result + str + (values[i] ? `<mark>${values[i]}</mark>` : '');
}, '');
}
const highlighted = highlight`Hello ${name}, you are ${age} years old`;
// 'Hello <mark>John</mark>, you are <mark>30</mark> years old'Enhanced Object Literals
// Property shorthand
const name = 'John';
const age = 30;
// Old way
const person1 = { name: name, age: age };
// ES6 way
const person2 = { name, age };
// Method shorthand
const obj = {
// Old way
greet: function() {
console.log('Hello');
},
// ES6 way
greet() {
console.log('Hello');
},
// Async method
async fetchData() {
const data = await fetch('/api/data');
return data.json();
}
};
// Computed property names
const propName = 'score';
const game = {
[propName]: 100,
[`${propName}Max`]: 1000,
['player' + 1]: 'John'
};
console.log(game); // { score: 100, scoreMax: 1000, player1: 'John' }Classes
// ES6 Classes
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(`Hello, I'm ${this.name}`);
}
// Static method
static create(name, age) {
return new Person(name, age);
}
// Getter
get info() {
return `${this.name} (${this.age})`;
}
// Setter
set info(value) {
const [name, age] = value.split(' ');
this.name = name;
this.age = parseInt(age);
}
}
const john = new Person('John', 30);
john.greet(); // Hello, I'm John
console.log(john.info); // John (30)
// Inheritance
class Employee extends Person {
constructor(name, age, jobTitle) {
super(name, age); // Call parent constructor
this.jobTitle = jobTitle;
}
greet() {
super.greet(); // Call parent method
console.log(`I work as a ${this.jobTitle}`);
}
}
const emp = new Employee('Jane', 28, 'Developer');
emp.greet();
// Hello, I'm Jane
// I work as a DeveloperModules (Import/Export)
// utils.js - Named exports
export const PI = 3.14159;
export function add(a, b) {
return a + b;
}
export class Calculator {
// ...
}
// Or export all at once
const PI = 3.14159;
function add(a, b) {
return a + b;
}
export { PI, add };
// Default export (one per file)
export default function multiply(a, b) {
return a * b;
}
// Or
function multiply(a, b) {
return a * b;
}
export default multiply;
// Importing
import multiply from './utils.js'; // Default import
import { PI, add } from './utils.js'; // Named imports
import multiply, { PI, add } from './utils.js'; // Both
import * as utils from './utils.js'; // All as namespace
// Rename imports
import { add as sum } from './utils.js';
// Re-exporting
export { add } from './utils.js';
export * from './utils.js';Default Parameters & Rest/Spread
// Default parameters
function greet(name = 'Guest', greeting = 'Hello') {
return `${greeting}, ${name}!`;
}
console.log(greet()); // 'Hello, Guest!'
console.log(greet('John')); // 'Hello, John!'
console.log(greet('John', 'Hi')); // 'Hi, John!'
// Computed default values
function createUser(name, id = Date.now()) {
return { name, id };
}
// Rest parameters
function sum(...numbers) {
return numbers.reduce((total, n) => total + n, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 15
// Spread in function calls
const nums = [1, 2, 3];
console.log(Math.max(...nums)); // 3Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free