JavaScript Fundamentals and ES6+ Features

JavaScript is the programming language of the web. It allows you to add interactivity, handle data, update content dynamically, and much more. Over the years, JavaScript has evolved significantly. In 2015, ECMAScript 6 (commonly called ES6) introduced many powerful new features that make JavaScript easier to write and maintain.

In this lesson, we’ll explore essential modern JavaScript (ES6+) features: let and const, arrow functions, template literals, destructuring and spread/rest operators, modules with imports/exports, and asynchronous programming using promises and async/await.

let, const, and arrow functions

let and const

Before ES6, developers used var to declare variables. However, var has function scope, which can lead to unexpected bugs. ES6 introduced let and const, which have block scope (the scope inside curly braces {}).

let: Used when you expect the variable’s value to change.

javascript
1
2
let count = 0;
count = 1; // allowed

const: Used when you do not want to reassign the variable. It does not mean the value itself is immutable (for objects and arrays, you can still modify properties).

javascript
1
2
3
4
5
const name = "Alice";
// name = "Bob"; Error: assignment to constant variable

const person = { age: 25 };
person.age = 26; // allowed

Arrow functions

Arrow functions provide a shorter syntax for writing functions and also handle the this keyword differently (useful when working with callbacks).

Example:

javascript
1
2
3
4
5
6
7
8
9
// Traditional function
function add(a, b) {
  return a + b;
}

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

console.log(add(2, 3)); // 5

If your function body is a single expression, you can omit the return keyword and braces {}.

Copilot prompt example:

1
// Write an arrow function that multiplies two numbers

Template literals

Template literals (backticks: `) allow you to embed variables directly into strings without messy concatenation.

Example:

javascript
1
2
3
4
5
const firstName = "Jane";
const age = 28;

const greeting = `Hello, my name is ${firstName} and I am ${age} years old.`;
console.log(greeting);

You can also create multiline strings easily:

javascript
1
2
3
4
const message = `This is a long message
that spans multiple lines
without using concatenation.`;
console.log(message);

Copilot prompt example:

1
// Create a template literal that outputs a user's name and city

Destructuring and spread/rest operators

Destructuring

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

Array destructuring:

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

Object destructuring:

javascript
1
2
3
const user = { name: "Sam", age: 30 };
const { name, age } = user;
console.log(name, age); // Sam 30

Spread operator (...)

The spread operator copies elements or properties into new arrays or objects.

Example with arrays:

javascript
1
2
3
const arr1 = [1, 2];
const arr2 = [...arr1, 3, 4];
console.log(arr2); // [1, 2, 3, 4]

Example with objects:

javascript
1
2
3
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 };
console.log(obj2); // { a: 1, b: 2, c: 3 }

Rest operator (...)

Used to collect remaining elements into an array or object.

Example in functions:

javascript
1
2
3
4
5
function sum(...numbers) {
  return numbers.reduce((total, num) => total + num, 0);
}

console.log(sum(1, 2, 3)); // 6

Copilot prompt example:

javascript
1
// Write a function that takes any number of arguments and returns their product using rest parameters

Modules and imports/exports

Modern JavaScript supports modules natively, making it easier to split code into reusable files.

Exporting from a module:

javascript
1
2
3
4
5
6
// utils.js
export function greet(name) {
  return `Hello, ${name}!`;
}

export const PI = 3.14159;

Importing in another file:

javascript
1
2
3
4
import { greet, PI } from "./utils.js";

console.log(greet("Tom")); // Hello, Tom!
console.log(PI);           // 3.14159

You can also export a single default value:

javascript
1
2
3
4
5
import add from "./math.js";
export default function add(a, b) {
  return a + b;
}
console.log(add(5, 3)); // 8

Copilot prompt example:

1
// Export a function that doubles a number and import it in another file

Promises and async/await

Promises

Promises simplify handling asynchronous operations (e.g., API calls).

Basic example:

javascript
1
2
3
4
5
6
7
8
9
10
11
const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("Data fetched successfully!");
    }, 2000);
  });
};

fetchData()
  .then((data) => console.log(data))
  .catch((error) => console.error(error));

async/await

async/await is syntactic sugar over promises, making asynchronous code look and behave more like synchronous code.

Example:

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const fetchData = () => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve("Data loaded!");
    }, 1500);
  });
};

async function load() {
  console.log("Fetching data...");
  const result = await fetchData();
  console.log(result);
}

load();

Copilot prompt example:

1
// Write an async function that fetches user data and logs it

Final thoughts

Mastering modern JavaScript (ES6+) features is critical for writing cleaner, more expressive, and maintainable code.

  • let and const help avoid common scoping bugs.
  • Arrow functions provide concise syntax and better handling of this.
  • Template literals make string building easier and more readable.
  • Destructuring and spread/rest operators simplify working with arrays and objects.
  • Modules allow for modular, reusable code.
  • Promises and async/await make handling asynchronous tasks straightforward and more readable.

Practicing these features, especially using Copilot prompts to experiment, will help you internalize modern JavaScript patterns and prepare you for working confidently in React and beyond.

Frequently Asked Questions