Skip to content
EzzyWeb

Level 4, Real Data & Architecture, Chapter 19 of 24

Modern JavaScript — ES6+ Classes & Modules

Why this matters

Every JavaScript feature you've used so far, functions, objects, arrays, has lived comfortably in a single file. But real applications split their code across many files, each responsible for one clear job, and describe reusable blueprints for creating similar objects again and again, like users, products, or movies. This chapter introduces the two tools that make that possible: classes and modules.

This is also the final concept chapter of this level, and it leads directly into your capstone project: a Movie Explorer App that fetches data from an API, organizes it with classes, and splits its code across modules. Everything from arrays and objects through async JavaScript, storage, and CSS architecture comes together here, so take your time and make sure these foundations feel solid.

The lesson

Classes as blueprints for objects

You already know how to create individual objects with object literals. A class is a template for creating many objects that share the same shape and behavior. You define one with the class keyword, give it a constructor method that runs when a new instance is created, and add regular methods that every instance can call. Inside the class, this refers to the specific instance the method was called on, exactly like the this you've already seen in DOM event handlers. You create an instance with the new keyword, which runs the constructor and hands you back a fully formed object.

A simple class
JavaScript
1class Movie {2  constructor(title, year, rating) {3    this.title = title;4    this.year = year;5    this.rating = rating;6  }78  describe() {9    return `${this.title} (${this.year}) — rated ${this.rating}/10`;10  }1112  isTopRated() {13    return this.rating >= 8;14  }15}1617const inception = new Movie("Inception", 2010, 8.8);18console.log(inception.describe());19console.log(inception.isTopRated()); // true
Every Movie instance shares the same methods but has its own data.

Classes can also extend one another with extends, letting a more specific class inherit everything from a general one and add or override behavior. Inside a subclass's constructor, calling super(...) runs the parent class's constructor first, which is required before you can use this. Inheritance is powerful but easy to overuse: reach for it when you truly have an 'is-a' relationship, like a DocumentaryMovie being a kind of Movie with an extra property, rather than forcing unrelated things to share a parent class just to avoid repeating a little code.

Extending a class
JavaScript
1class DocumentaryMovie extends Movie {2  constructor(title, year, rating, subject) {3    super(title, year, rating);4    this.subject = subject;5  }67  describe() {8    return `${super.describe()} — about ${this.subject}`;9  }10}1112const doc = new DocumentaryMovie("Free Solo", 2018, 8.1, "rock climbing");13console.log(doc.describe());
DocumentaryMovie inherits everything Movie already does.

Modules: splitting code across files

As a project grows, keeping everything in one JavaScript file becomes unmanageable. ES modules let you split code into separate files and explicitly control what's shared between them using export and import. A file can export a class, function, or value by name, and any other file can import exactly what it needs. This makes dependencies explicit: reading the top of a file tells you exactly what it relies on, instead of hoping some global variable was defined somewhere else earlier. To use modules in the browser, your script tag needs type="module", which also means the file runs in strict mode automatically.

Exporting and importing between files
JavaScript
1// movie.js2export class Movie {3  constructor(title, rating) {4    this.title = title;5    this.rating = rating;6  }7}89export const RATING_THRESHOLD = 8;1011// app.js12import { Movie, RATING_THRESHOLD } from "./movie.js";1314const film = new Movie("Arrival", 7.9);15console.log(film.rating >= RATING_THRESHOLD);
movie.js defines the class, app.js uses it.

Modules also support a single export default per file, useful when a file's whole purpose is to provide one main thing, like a single class or a single configuration object; you import a default export without curly braces and can name it whatever you like on the way in. Combining classes and modules gives you the same architecture used in production applications: each file defines one clear responsibility (a Movie class, a fetchMovies function, a rendering helper), and your main script wires them together by importing what it needs.

  • class defines a blueprint with a constructor and methods
  • new ClassName(...) creates an instance, running the constructor
  • extends lets a class inherit from another, super() calls the parent constructor
  • export shares a class, function, or value from a file
  • import { name } from "./file.js" brings named exports into another file
  • export default marks one primary export per file, imported without braces

Together, this chapter closes the loop on everything Level 4 has covered. You now know how to shape data with array methods and objects, fetch real data asynchronously and handle its successes and failures, persist state across reloads, style a growing project with a real architecture, and organize the JavaScript itself into classes and modules. The capstone Movie Explorer App is designed to make you use every one of these skills together, which is exactly what building a real application feels like.

Try it yourself

This sandbox uses a class and simulated module-style organization within one file (since the sandbox runs as a single script) to model movies and render them.

Live preview

Chapter boss project

Capstone Kickoff: Movie Explorer App

This project launches your Level 4 capstone: a Movie Explorer App. Design a Movie class that models a film with properties like title, year, rating, and genre, and methods like isTopRated() or matchesSearch(term). Then organize your project into separate module files: one for the Movie class, one for fetching data (real API or a local simulated dataset), and one main file that wires everything together and renders to the DOM.

The app should fetch a list of movies, render them as cards using your class's methods, and let the user search or filter using the array techniques and DOM skills from earlier chapters. Persist the user's last search term in localStorage so it's restored on reload, and use async/await with proper error handling for the fetch.

This is intentionally the most complete project so far, bringing together classes, modules, fetch, async/await, storage, and CSS architecture with custom properties and BEM naming. Build it incrementally: get static rendering working first, then add fetching, then search, then persistence, then polish the styling.

  • Start with your Movie class and a hardcoded array of instances before wiring up any fetch call, so you can build and test your rendering logic in isolation.
  • Keep your files small and focused: movie.js for the class, api.js for fetching and error handling, app.js for orchestration and DOM updates.
  • Reuse your loadJSON-with-default localStorage pattern from the browser storage chapter for restoring the last search term.
  • Style your cards with BEM class names and custom properties from the start, so adding dark mode later requires no structural changes.

Level-up checklist

Tick these off once each one is true for you.