Beginner's Guide to JavaScript ES6+ Features

author

By Freecoderteam

Sep 20, 2025

1

image

Beginner's Guide to JavaScript ES6+ Features

JavaScript, one of the most widely used programming languages, has evolved significantly over the years. With the introduction of ECMAScript 2015 (ES6) and subsequent updates, JavaScript has become more concise, expressive, and developer-friendly. In this blog post, we’ll explore some of the most useful ES6+ features, providing practical examples, best practices, and actionable insights for beginners.


Table of Contents


1. Introduction to ES6+

ES6, officially released in 2015, brought a plethora of new features to JavaScript, making it more modern and powerful. Since then, ECMAScript has continued to evolve, introducing features in subsequent updates (ES7, ES8, etc.). These features aim to make JavaScript code cleaner, more maintainable, and more efficient.

In this guide, we’ll focus on some of the most impactful ES6+ features that every beginner should know:

  • let and const
  • Arrow functions
  • Template literals
  • Destructuring assignment
  • Spread and rest operators
  • Classes
  • Promises and async/await
  • Modules

2. let and const

Before ES6, JavaScript only had the var keyword for variable declaration. However, var has some quirks, such as function-level scoping and hoisting, which can lead to confusion. ES6 introduced let and const to provide block-level scoping and immutability.

let

let allows you to declare variables that are block-scoped (inside {} blocks). This prevents accidental redeclarations and helps avoid bugs.

// Using `var` (function scope)
function example() {
  if (true) {
    var x = 10;
  }
  console.log(x); // Output: 10
}

example();

// Using `let` (block scope)
function example2() {
  if (true) {
    let y = 20;
  }
  console.log(y); // Error: y is not defined
}

example2();

const

const is similar to let, but the variable cannot be reassigned once initialized. It’s ideal for declaring constants or values that shouldn’t change.

const PI = 3.14159;
PI = 3; // Error: Assignment to constant variable.

// Note: Objects and arrays declared with `const` can still be mutated.
const numbers = [1, 2, 3];
numbers.push(4); // This is allowed
console.log(numbers); // Output: [1, 2, 3, 4]

Best Practices

  • Use const for values that won’t change.
  • Use let for variables that need to be reassigned.
  • Avoid var unless you specifically need function-level scoping.

3. Arrow Functions

Arrow functions (=>) are a concise way to write function expressions. They are particularly useful for callbacks and one-liners.

Syntax

// Regular function
function add(a, b) {
  return a + b;
}

// Arrow function
const add = (a, b) => a + b;

Implicit Return

If the function body is a single expression, the curly braces and return keyword are optional.

const multiply = (a, b) => a * b; // Single expression
const greet = name => `Hello, ${name}`; // Single expression with template literal

Arrow Functions with Multiple Lines

For functions with multiple lines, you need to use curly braces and explicitly return.

const calculate = (a, b) => {
  const sum = a + b;
  const product = a * b;
  return { sum, product };
};

console.log(calculate(3, 4)); // Output: { sum: 7, product: 12 }

Best Practices

  • Use arrow functions for concise callbacks and one-liners.
  • Avoid arrow functions for complex functions or when this binding is important (since arrow functions don’t bind this).

4. Template Literals

Template literals are a more readable way to create strings with embedded expressions. They use backticks (`) instead of single or double quotes.

Basic Usage

const name = "Alice";
const age = 25;
const message = `Hello, my name is ${name} and I am ${age} years old.`;
console.log(message); // Output: Hello, my name is Alice and I am 25 years old.

Multi-line Strings

Template literals allow you to write multi-line strings without concatenation.

const poem = `Roses are red,
Violets are blue,
All's well that ends well.`;
console.log(poem);
// Output:
// Roses are red,
// Violets are blue,
// All's well that ends well.

Tagged Templates

You can also use tagged templates to process template literals.

function highlight(str, ...tags) {
  return str
    .map((segment, i) => (tags[i] ? `<span style="color:red">${segment}</span>` : segment))
    .join("");
}

const result = highlight`This is ${"important"}`;
console.log(result); // Output: This is <span style="color:red">important</span>

Best Practices

  • Use template literals for strings that contain embedded expressions or multi-line text.
  • Avoid overly complex template literals to maintain readability.

5. Destructuring Assignment

Destructuring allows you to extract values from arrays or objects into distinct variables in a concise way.

Array Destructuring

const numbers = [1, 2, 3];
const [a, b, c] = numbers;
console.log(a, b, c); // Output: 1 2 3

// Skipping elements
const [x, , z] = numbers;
console.log(x, z); // Output: 1 3

Object Destructuring

const person = { name: "Bob", age: 30, city: "New York" };
const { name, age } = person;
console.log(name, age); // Output: Bob 30

// Renaming properties
const { city: location } = person;
console.log(location); // Output: New York

Default Values

You can provide default values for missing properties or array elements.

const [p1 = "Default", p2] = [undefined, "Second"];
console.log(p1, p2); // Output: Default Second

const { name: userName = "Guest" } = {};
console.log(userName); // Output: Guest

Best Practices

  • Use destructuring to simplify property access and improve code readability.
  • Avoid deeply nested destructuring, as it can reduce readability.

6. Spread and Rest Operators

The spread (...) and rest (...) operators are powerful tools for working with iterables (arrays, strings, etc.).

Spread Operator

The spread operator allows you to expand an iterable into individual elements.

const arr1 = [1, 2];
const arr2 = [3, 4];
const combined = [...arr1, ...arr2, 5];
console.log(combined); // Output: [1, 2, 3, 4, 5]

// Copying arrays
const copy = [...arr1];
console.log(copy); // Output: [1, 2]

Rest Operator

The rest operator allows you to collect multiple arguments into an array.

function sum(...numbers) {
  return numbers.reduce((total, num) => total + num, 0);
}

console.log(sum(1, 2, 3, 4)); // Output: 10

Best Practices

  • Use the spread operator to combine or copy iterables.
  • Use the rest operator for functions that accept a variable number of arguments.

7. Classes

ES6 introduced a class syntax for creating objects, which is a syntactic sugar over JavaScript's prototype-based inheritance.

Simple Class

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  greet() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }
}

const alice = new Person("Alice", 25);
alice.greet(); // Output: Hello, my name is Alice and I am 25 years old.

Inheritance

Classes support inheritance using the extends keyword.

class Student extends Person {
  constructor(name, age, grade) {
    super(name, age); // Call the parent constructor
    this.grade = grade;
  }

  study() {
    console.log(`${this.name} is studying hard!`);
  }
}

const bob = new Student("Bob", 20, "A");
bob.greet(); // Output: Hello, my name is Bob and I am 20 years old.
bob.study(); // Output: Bob is studying hard!

Best Practices

  • Use classes for object-oriented programming and inheritance.
  • Avoid overusing classes for simple tasks where plain objects or functions might suffice.

8. Promises and async/await

Promises provide a way to handle asynchronous operations in a cleaner manner than callbacks. ES8 introduced async and await to simplify Promise-based code.

Promises

function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("Data fetched successfully!");
    }, 1000);
  });
}

fetchData()
  .then(data => console.log(data)) // Output: Data fetched successfully!
  .catch(error => console.error(error));

async and await

async functions return Promises, and await allows you to "pause" execution until a Promise is resolved.

async function fetchAndDisplayData() {
  try {
    const data = await fetchData();
    console.log(data); // Output: Data fetched successfully!
  } catch (error) {
    console.error(error);
  }
}

fetchAndDisplayData();

Best Practices

  • Use Promises for handling asynchronous operations.
  • Use async/await for writing asynchronous code in a synchronous style.

9. Modules

ES6 introduced a built-in module system for JavaScript, allowing you to import and export code across files.

Exporting

// math.js
export function add(a, b) {
  return a + b;
}

export const PI = 3.14159;

Importing

// app.js
import { add } from "./math.js";
import { PI } from "./math.js";

console.log(add(2, 3)); // Output: 5
console.log(PI); // Output: 3.14159

Default Export

// util.js
export default function logger(message) {
  console.log(message);
}

// app.js
import logger from "./util.js";
logger("This is a log message."); // Output: This is a log message.

Best Practices

  • Use modules to organize your code into reusable components.
  • Avoid importing too many modules in a single file to keep dependencies manageable.

10. Best Practices and Recommendations

  • Choose the Right Tool: Use let for reassignable variables, const for constants, and var only when necessary.
  • Keep Functions Concise: Use arrow functions for simple callbacks but avoid them for complex functions.
  • Use Destructuring for Readability: Destructure objects and arrays to improve code clarity.
  • Embrace Async/Await: Use async/await for better readability of asynchronous code.
  • Organize with Modules: Modularize your code to keep it maintainable and reusable.

11. Conclusion

ES6+ has revolutionized JavaScript, making it more expressive and developer-friendly. By mastering features like let, const, arrow functions, template literals, destructuring, spread/rest operators, classes, Promises, async/await, and modules, you’ll be well-equipped to write modern, efficient, and maintainable JavaScript code.

As you continue your journey in JavaScript, don’t hesitate to explore additional ES features and libraries to further enhance your skills. Happy coding!


This guide should give you a solid foundation in ES6+ features. Practice these concepts in your projects to reinforce your understanding and build confidence in modern JavaScript development.

Subscribe to Receive Future Updates

Stay informed about our latest updates, services, and special offers. Subscribe now to receive valuable insights and news directly to your inbox.

No spam guaranteed, So please don’t send any spam mail.