Topic 48 of 48 · Full Stack Essentials

JavaScript Misc

Lesson TL;DRTopic 11: JavaScript Misc 📖 13 min read · 🎯 advanced · 🧭 Prerequisites: javascriptmapobject, registrationform Why this matters Up until now, you've been writing JavaScript the long way — gluing str...
13 min read·advanced·javascript · template-literals · destructuring · spread-rest

Topic 11: JavaScript Misc

📖 13 min read · 🎯 advanced · 🧭 Prerequisites: javascript-map-object, registration-form

Why this matters

Up until now, you've been writing JavaScript the long way — gluing strings together with +, pulling values out of objects one by one, and hoping your API calls don't fail silently. Here's the thing — real-world JavaScript code looks nothing like that. On the job, you'll constantly reach for a handful of tools: template literals, destructuring, spread, rest, and promises. These aren't fancy extras. They're the shortcuts every developer uses daily to write cleaner, faster, more readable code. Let's get you comfortable with them.

What You'll Learn

  • Write cleaner strings using template literals and multiline syntax
  • Extract array elements and object properties with destructuring
  • Merge and collect data using spread and rest operators (...)
  • Create and consume Promises with .then() and .catch()
  • Write async/await functions that read like synchronous code
  • Build a real working API fetch tied to a button click

The Analogy

Think of a postal dispatch rider (the async function) who leaves the city gates with an order slip (the Promise). The rider sets off immediately, and the city carries on its business — nobody stands frozen at the gate waiting. When the rider finally returns with a parcel (the resolved value), the clerk at the desk picks it up and processes it, exactly as arranged. If the rider comes back empty-handed because the road was washed out (rejection), a backup plan (.catch() or try/catch) kicks in. The city never stopped; it just handled the result when it arrived.

Chapter 1: Template Literals

Template literals let you embed variables and expressions directly inside strings without string concatenation. Instead of single or double quotes, you wrap the string in backticks (`), and insert dynamic values with ${}.

Basic syntax

let name = "Alice";
let age = 25;

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

Any valid JavaScript expression works inside ${} — arithmetic, function calls, ternaries, anything.

Multiline strings

Template literals preserve real line breaks, so you no longer need \n or concatenation:

let multiline = `This is a string
that spans across
multiple lines.`;

console.log(multiline);

Output:

This is a string
that spans across
multiple lines.

This is especially useful for building HTML fragments or SQL strings inline.

Chapter 2: Destructuring

Destructuring is a shorthand that extracts values from arrays or properties from objects directly into named variables — one line instead of many assignments.

Array Destructuring

Position in the array determines which variable gets which value:

let colors = ["red", "green", "blue"];

let [firstColor, secondColor, thirdColor] = colors;

console.log(firstColor);  // red
console.log(secondColor); // green
console.log(thirdColor);  // blue

You can skip elements by leaving a gap: let [first, , third] = colors;

Object Destructuring

Property names in the pattern must match keys in the object:

let person = {
    name: "Alice",
    age: 25,
    city: "Vizag"
};

let { name, age, city } = person;

console.log(name); // Alice
console.log(age);  // 25
console.log(city); // Vizag

You can rename while destructuring: let { name: fullName } = person; gives you fullName instead of name.

flowchart LR
    A["person object\n{ name, age, city }"] -->|destructure| B["const { name, age, city }"]
    B --> C[name = 'Alice']
    B --> D[age = 25]
    B --> E[city = 'Vizag']

Chapter 3: Spread and Rest Operators

Both features use the same three-dot token (...), but they do opposite things depending on context.

Spread Operator

The spread operator expands an iterable (array or object) into individual elements. Use it to merge arrays, clone objects, or pass array elements as function arguments:

let array1 = [1, 2, 3];
let array2 = [4, 5, 6];

let combinedArray = [...array1, ...array2];
console.log(combinedArray); // [1, 2, 3, 4, 5, 6]

Spreading objects merges their key-value pairs — later keys overwrite earlier ones:

let person = { name: "Alice", age: 25 };

let extendedPerson = { ...person, city: "Vizag" };
console.log(extendedPerson); // { name: "Alice", age: 25, city: "Vizag" }

Rest Operator

The rest operator collects remaining arguments or array elements into a single array. It always appears last in a parameter list:

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

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

numbers here is a real array, so all array methods (.reduce, .map, .filter) work on it.

flowchart LR
    subgraph Spread
        S1["[...arr1, ...arr2]"] --> S2["[1,2,3,4,5,6]"]
    end
    subgraph Rest
        R1["sum(1,2,3,4)"] --> R2["...numbers = [1,2,3,4]"]
    end

Chapter 4: Promises

A Promise is an object that represents the eventual result of an asynchronous operation. It can be in one of three states: pending, fulfilled (resolved), or rejected.

Creating a Promise

The Promise constructor takes an executor function with two callbacks: resolve (success) and reject (failure):

let promise = new Promise((resolve, reject) => {
    let isSuccessful = true;

    if (isSuccessful) {
        resolve("Operation was successful!");
    } else {
        reject("Operation failed!");
    }
});

promise
    .then((message) => {
        console.log(message); // Operation was successful!
    })
    .catch((error) => {
        console.log(error);
    });
  • .then() runs when the promise resolves (happy path).
  • .catch() runs when the promise rejects (error path).
  • You can chain multiple .then() calls to transform the value at each step.
stateDiagram-v2
    [*] --> Pending
    Pending --> Fulfilled : resolve()
    Pending --> Rejected : reject()
    Fulfilled --> [*] : .then() runs
    Rejected --> [*] : .catch() runs

Chapter 5: Async/Await

async/await is syntactic sugar over Promises. It lets you write asynchronous code that reads like synchronous code — no chained .then() calls required.

  • Prefix a function with async and it automatically returns a Promise.
  • Use await inside an async function to pause execution until the awaited Promise settles.
function fetchData() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve("Data fetched");
        }, 2000);
    });
}

async function getData() {
    console.log("Fetching data...");
    let data = await fetchData();
    console.log(data); // Data fetched  (printed after 2 seconds)
}

getData();

Execution does not freeze — await yields control back to the event loop and resumes the function when the Promise resolves. Wrap await calls in try/catch to handle rejections cleanly.

Chapter 6: Practical Example — Fetching Data from an API

the trainer's favorite territory: live HTTP requests. The class built a small page that fires a real fetch() call to the public JSONPlaceholder API when a button is clicked.

HTML (index.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>API Data Fetch Example</title>
</head>
<body>
    <h1>API Data Fetch Example</h1>
    <button id="fetchButton">Fetch Data</button>
    <pre id="dataDisplay"></pre>

    <script src="app.js"></script>
</body>
</html>

JavaScript (app.js)

document.getElementById("fetchButton").addEventListener("click", async () => {
    let dataDisplay = document.getElementById("dataDisplay");
    dataDisplay.textContent = "Fetching data...";

    try {
        let response = await fetch("https://jsonplaceholder.typicode.com/posts/1");
        let data = await response.json();
        dataDisplay.textContent = JSON.stringify(data, null, 2);
    } catch (error) {
        dataDisplay.textContent = "Error fetching data";
    }
});

Walk-through of what happens on click:

  1. The <pre> element immediately shows "Fetching data..." (user feedback).
  2. await fetch(...) fires an HTTP GET to JSONPlaceholder and waits for the response headers.
  3. await response.json() reads the response body and parses it as JSON.
  4. JSON.stringify(data, null, 2) pretty-prints the object with 2-space indentation into the <pre>.
  5. If the network fails or the server errors, catch displays a friendly message instead of crashing.
sequenceDiagram
    participant Browser
    participant app.js
    participant JSONPlaceholder

    Browser->>app.js: click #fetchButton
    app.js->>app.js: show "Fetching data..."
    app.js->>JSONPlaceholder: GET /posts/1
    JSONPlaceholder-->>app.js: 200 OK (JSON body)
    app.js->>app.js: response.json()
    app.js->>Browser: render JSON in <pre>

🧪 Try It Yourself

Task: Extend the API fetch page to load a different post each time the button is clicked.

  1. Add a <input type="number" id="postId" value="1" min="1" max="100"> above the button in index.html.
  2. In app.js, read its value: let id = document.getElementById("postId").value;
  3. Build the URL dynamically using a template literal: `https://jsonplaceholder.typicode.com/posts/${id}`
  4. Replace the hardcoded URL in the fetch call with your new template-literal URL.

Starter snippet:

document.getElementById("fetchButton").addEventListener("click", async () => {
    let id = document.getElementById("postId").value;
    let dataDisplay = document.getElementById("dataDisplay");
    dataDisplay.textContent = "Fetching data...";

    try {
        let response = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
        let data = await response.json();
        dataDisplay.textContent = JSON.stringify(data, null, 2);
    } catch (error) {
        dataDisplay.textContent = "Error fetching data";
    }
});

Success criterion: Typing 5 in the input and clicking the button should show post #5's title and body in the <pre> without a page reload.

🔍 Checkpoint Quiz

Q1. What character wraps a template literal, and how do you embed a variable inside it?

Q2. Given the following code, what is printed to the console?

let coords = [10, 20, 30];
let [x, , z] = coords;
console.log(`x=${x}, z=${z}`);

A) x=10, z=20 B) x=10, z=30 C) x=20, z=30 D) x=10, z=undefined

Q3. What does the rest operator (...) do when used in a function parameter list?

A) Copies every argument into a new object B) Collects remaining arguments into an array C) Spreads the first argument across multiple variables D) Converts the function to an async function

Q4. You are building a page that calls a weather API on button click and displays the result. The API call takes up to 3 seconds. How would you prevent the browser from freezing while waiting, and how would you handle a network failure gracefully?

A1. Backticks (`) wrap template literals. Variables and expressions are embedded with ${} — for example `Hello, ${name}!`. This eliminates string concatenation with +.

A2. B) x=10, z=30 — the gap (, ,) skips index 1 (value 20), so x gets index 0 (10) and z gets index 2 (30).

A3. B) Collects remaining arguments into an array. The rest parameter gathers every argument beyond the named ones into a real array, making variable-arity functions easy to write without touching arguments.

A4. Mark the event handler async, use await fetch(...) so the browser's event loop stays free during the 3-second wait, and wrap the await calls in a try/catch block. In the catch, update the page with a user-friendly error message instead of letting the uncaught rejection propagate.

🪞 Recap

  • Template literals use backticks and ${} to embed expressions in strings, and they naturally support multiline content.
  • Destructuring unpacks array positions or object properties into named variables in one concise statement.
  • The spread operator (...) expands iterables into individual elements; the rest operator collects remaining items into an array.
  • A Promise wraps an asynchronous result with .then() for success and .catch() for errors.
  • async/await makes Promise-based code read sequentially — pair it with try/catch to handle rejections cleanly.

📚 Further Reading

Like this topic? It’s one of 48 in Full Stack Essentials.

Block your seat for ₹2,500 and join the next cohort.