JavaScript Classes and Modules
As projects grow, you need more than scattered functions and variables — you need organized code structure. Classes provide object-oriented patterns, and Modules provide file-level code isolation. Together, they form the foundation of modern JS projects.
Class Syntax
A Class is a template for creating objects — syntactic sugar over constructor functions.
<script>
class ClassName {
constructor(params) {
this.property = params;
}
method() {
// ...
}
}
</script>
Example: Creating a Student Class
<div id="output" style="padding: 10px; border: 1px solid #ccc;"></div>
<script>
const output = document.getElementById('output');
class Student {
constructor(name, age, grade) {
this.name = name;
this.age = age;
this.grade = grade;
}
introduce() {
return 'My name is ' + this.name + ', I am ' + this.age + ' years old, in grade ' + this.grade + '.';
}
study(subject) {
return this.name + ' is studying ' + subject + '.';
}
}
const s1 = new Student('Alice', 12, '6th');
const s2 = new Student('Bob', 11, '5th');
output.textContent = s1.introduce() + '\n' + s2.introduce() + '\n' + s1.study('Math');
</script>
class is essentially syntactic sugar over constructor functions + prototypes. new Student() works the same as the old new function Student(), but the syntax is cleaner and more intuitive.
Properties and Methods
Instance Properties and Methods
Properties and methods defined with this.xxx inside constructor belong to the instance — each object gets its own copy.
Static Methods
Methods defined with the static keyword belong to the class itself, not to instances. Call them via ClassName.method().
Getters and Setters
Use get and set keywords to define "virtual properties" — functions that execute automatically on read/write.
<div id="output" style="white-space: pre; font-family: monospace; padding: 10px; border: 1px solid #ccc;"></div>
<script>
const output = document.getElementById('output');
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
get fullName() {
return this.firstName + ' ' + this.lastName;
}
set fullName(value) {
const parts = value.split(' ');
this.firstName = parts[0];
this.lastName = parts[1];
}
}
const p = new Person('John', 'Doe');
output.textContent = 'fullName: ' + p.fullName + '\n';
p.fullName = 'Jane Smith';
output.textContent += 'After change: ' + p.fullName;
</script>
Example: Static Methods and Getters/Setters
<div id="output" style="white-space: pre; font-family: monospace; padding: 10px; border: 1px solid #ccc;"></div>
<script>
const output = document.getElementById('output');
class Circle {
static count = 0;
constructor(radius) {
this.radius = radius;
Circle.count++;
}
get area() {
return Math.PI * this.radius * this.radius;
}
get diameter() {
return this.radius * 2;
}
set diameter(value) {
this.radius = value / 2;
}
static createUnit() {
return new Circle(1);
}
}
const c1 = new Circle(5);
const c2 = new Circle(10);
const c3 = Circle.createUnit();
output.textContent = 'Circle with radius 5:\n';
output.textContent += ' Area: ' + c1.area.toFixed(2) + '\n';
output.textContent += ' Diameter: ' + c1.diameter + '\n';
output.textContent += ' Set diameter to 20:\n';
c1.diameter = 20;
output.textContent += ' New radius: ' + c1.radius + '\n\n';
output.textContent += 'Total circles created: ' + Circle.count + '\n';
output.textContent += 'Unit circle radius: ' + c3.radius;
</script>
Inheritance
extends lets a child class inherit properties and methods from a parent class. super calls the parent's constructor or methods.
Example: Inheritance Demo
<div id="output" style="white-space: pre; font-family: monospace; padding: 10px; border: 1px solid #ccc;"></div>
<script>
const output = document.getElementById('output');
class Animal {
constructor(name, sound) {
this.name = name;
this.sound = sound;
}
speak() {
return this.name + ' says: ' + this.sound;
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name, 'Woof');
this.breed = breed;
}
fetch(item) {
return this.name + ' fetched the ' + item;
}
}
class Cat extends Animal {
constructor(name, indoor) {
super(name, 'Meow');
this.indoor = indoor;
}
purr() {
return this.name + ' is purring...';
}
}
const dog = new Dog('Rex', 'Shiba Inu');
const cat = new Cat('Whiskers', true);
output.textContent = dog.speak() + '\n';
output.textContent += dog.fetch('frisbee') + '\n';
output.textContent += cat.speak() + '\n';
output.textContent += cat.purr();
</script>
constructor, you must call super() before using this — because until the parent is initialized, the child's this doesn't exist. This is the easiest rule to forget when learning inheritance.
ES Modules
Modules are JS's code organization unit. One module = one file. Variables inside a module are private by default — only explicitly exported items are accessible externally.
Named Exports / Imports
<script>
// math.js
export const PI = 3.14;
export function add(a, b) { return a + b; }
// app.js
import { PI, add } from './math.js';
</script>
Default Exports / Imports
<script>
// logger.js
export default function log(msg) { console.log(msg); }
// app.js
import log from './logger.js';
</script>
Using Modules in HTML
Simply add type="module" to the script tag.
<script type="module">
import { add } from './math.js';
console.log(add(1, 2));
</script>
Example: Single-File Module Simulation (Inline Module)
In real projects, modules should be split into separate files. Here we simulate them within a single HTML file using type="module".
<div id="output" style="padding: 10px; border: 1px solid #ccc;"></div>
<script type="module">
const output = document.getElementById('output');
const calculator = {
add(a, b) { return a + b; },
subtract(a, b) { return a - b; },
multiply(a, b) { return a * b; },
divide(a, b) { return b !== 0 ? a / b : 'Cannot divide by zero'; }
};
const formatter = {
currency(value) { return '$' + value.toFixed(2); },
percent(value) { return (value * 100).toFixed(1) + '%'; }
};
const r1 = calculator.add(10, 20);
const r2 = calculator.multiply(5, 4);
const r3 = calculator.divide(10, 3);
output.textContent = '10 + 20 = ' + r1 + '\n';
output.textContent += '5 × 4 = ' + r2 + '\n';
output.textContent += '10 ÷ 3 = ' + formatter.currency(r3) + '\n';
output.textContent += '0.85 → ' + formatter.percent(0.85);
// In a real project you would split like this:
// calculator.js → export { calculator }
// formatter.js → export { formatter }
// main.js → import { calculator } from './calculator.js'
// import { formatter } from './formatter.js'
</script>
📖 Summary
classis syntactic sugar over constructors;constructoris the initializer, and methods are defined on the prototypestaticmethods belong to the class, not instances — ideal for utility and factory methodsget/setdefine virtual properties that intercept reads/writes for validation or computationextendsenables inheritance; a childconstructormust callsuper()first- ES modules use
export/importfor code isolation and reuse;type="module"enables them in HTML - Modules organize code by feature, enable lazy loading, and prevent global namespace pollution
❓ FAQ
Q: What's the real difference between a Class and a constructor function? A: No fundamental difference — Class is syntactic sugar. But Classes have a few traits: they must be called with
new(can't run as plain functions), methods are non-enumerable, and strict mode is on by default. The syntax is cleaner, so Classes are recommended.
Q: What's the difference between
importandrequire? A:importis ES module syntax — statically analyzed at compile time.requireis CommonJS (Node.js) — dynamically loaded at runtime. Browsers natively support only ES modules.importmust be at the top level;requirecan be anywhere.
Q: Can you mix default and named exports? A: Yes. A module can have one default export and multiple named exports:
export default App; export const utils = {};. Import with:import App, { utils } from './module.js'.
📝 Exercises
- Basic: Create a
Rectangleclass withwidthandheightproperties, plusgetArea()andgetPerimeter()methods. - Intermediate: Add a
get area()getter andset area(value)setter toRectangle(setting area adjusts width/height proportionally). Then create aSquaresubclass that extendsRectangle. - Challenge: Design an
EventManagerclass withon(event, callback),off(event, callback), andemit(event, data)methods to simulate a simple event system (hint: use an object mapping events to arrays of callbacks).



