JavaScript: Object-Oriented Programming
Learn how to model real-world concepts with constructor functions, prototypes, and ES6 classes.
Constructor Functions
A constructor function is a regular function used as a blueprint to create multiple objects with the same structure. By convention, constructor function names start with an uppercase letter.
Constructor Function
A constructor function defines the shape of an object, its properties are set via this inside the function body.
- Name starts with uppercase by convention:
Person, notperson - Properties are assigned with
this.property = valueinside the body - Must be called with the
newkeyword to work correctly - Methods placed on
ConstructorName.prototypeare shared across all instances
Constructor Function
Define a Person blueprint and share the greet method via the prototype.
Press Run to execute the code and see output here.
The new Keyword
Calling a function with new triggers four automatic steps that turn it into an object factory.
What new Does
new automates the boilerplate of creating and returning an object from a constructor.
- 1. Creates a brand-new empty object
- 2. Sets the new object's prototype to
Constructor.prototype - 3. Runs the constructor body with
thispointing to the new object - 4. Returns the new object automatically (unless the constructor explicitly returns a different object)
new Keyword
Without new the constructor returns nothing and this is wrong.
Press Run to execute the code and see output here.
Prototype Chain
Every JavaScript object has an internal link to another object called its prototype. When you access a property, JavaScript walks this chain of linked objects until it finds the property or reaches null.
Prototype Chain
The prototype chain is how JavaScript implements inheritance, shared properties live higher up the chain.
- Property lookup order: own properties first, then prototype, then prototype's prototype, and so on
- The chain ends at
Object.prototype, whose prototype isnull - Methods like
toString()andhasOwnProperty()are inherited fromObject.prototype
Prototype Chain Lookup
speak lives on Animal.prototype, not on dog, found via the chain.
Press Run to execute the code and see output here.
__proto__ vs prototype
These two look similar but serve different purposes: prototype is a property on constructor functions; __proto__ is the actual internal link on every object instance.
prototype vs __proto__
prototype is the template; __proto__ is the live link used during property lookup.
Function.prototype: the object that new instances will inherit frominstance.__proto__: points to the constructor's prototype object (same reference)- Use
Object.getPrototypeOf(obj)instead of__proto__in production code __proto__is a legacy accessor, avoid mutating it directly
prototype vs __proto__
Dog.prototype and rex.__proto__ point to the exact same object.
Press Run to execute the code and see output here.
Prototypal Inheritance
One constructor can inherit from another by linking its prototype to an instance of the parent, so instances of the child share the parent's methods.
Prototypal Inheritance
Linking prototypes lets child constructors reuse and extend parent behaviour without copying code.
- Use
Object.create(Parent.prototype)to set up the chain correctly - Call the parent constructor with
Parent.call(this, ...args)to copy own properties - Reset
Child.prototype.constructorback toChildafter linking - ES6
extendsdoes all of this automatically, prefer it for new code
Prototypal Inheritance
Dog inherits speak from Animal and adds its own bark method.
Press Run to execute the code and see output here.
ES6 Class Declaration
The class keyword is syntactic sugar over the prototype-based system. It provides a cleaner, more readable way to define constructor functions and their prototype methods.
class Declaration
Classes are the modern, recommended way to write object-oriented JavaScript.
- A class body is always in strict mode
- Classes are NOT hoisted like function declarations, define before use
- Methods defined inside the class body are placed on the prototype automatically
- Under the hood, a class is still a function:
typeof Person === "function"
Class Declaration
The class syntax is cleaner but produces the same prototype structure underneath.
Press Run to execute the code and see output here.
Static Methods
A static method belongs to the class itself, not to instances. Call it directly on the class name.
static Methods
Use static methods for utility functions that relate to the class but do not need instance data.
- Called as
ClassName.method(), notinstance.method() thisinside a static method refers to the class, not an instance- Common uses: factory helpers, validators, comparison functions
Static Method
fromFahrenheit is a factory that creates a Temperature without exposing the math.
Press Run to execute the code and see output here.
Getters and Setters
Getters and setters let you define properties that run logic when read or written, while looking like plain property access to the caller.
get / set
Getters and setters add validation or computed properties behind a simple property syntax.
get propName(): runs when the property is readset propName(value): runs when the property is assigned- Setters are ideal for validating incoming values before storing them
- A getter with no matching setter makes the property effectively read-only
Getters and Setters
area is computed on demand; the radius setter rejects negative values.
Press Run to execute the code and see output here.
Inheritance with extends
The extends keyword creates a subclass that inherits all methods from the parent class and can add or override them.
extends
extends sets up the prototype chain automatically, replacing the manual Object.create pattern.
- The subclass inherits all instance and static methods from the parent
- Override a method by redefining it in the subclass body
- Call the parent's version of a method with
super.methodName() - A subclass constructor MUST call
super()before usingthis
extends and Method Override
Dog overrides speak but still passes instanceof Animal checks.
Press Run to execute the code and see output here.
super Keyword
super has two uses: calling the parent constructor (super()) and calling a parent method (super.method()).
super
super lets a subclass reuse the parent's constructor and methods without duplicating code.
super(args)in a constructor: calls the parent constructorsuper.method()in a method: calls the parent's version of that method- Calling
super()is mandatory in a subclass constructor, omitting it throws a ReferenceError - You can call
super.method()even when you override the method, to extend rather than replace it
super in Constructor and Method
ElectricCar builds on Vehicle's describe() using super.describe().
Press Run to execute the code and see output here.
Encapsulation and Private Fields
Encapsulation means hiding internal state and only exposing what the outside world needs. ES2022 introduced true private fields with the # prefix.
Private Fields (#)
Fields prefixed with # are strictly private, accessing them from outside the class throws a SyntaxError.
- Declare at the top of the class body:
#fieldName; - Only methods inside the same class can read or write them
- Unlike the
_convention, the # prefix is enforced by the language itself - Private methods are also supported:
#methodName() { }
Private Fields
#balance is enforced private, only accessible through the public getter and deposit method.
Press Run to execute the code and see output here.
| Pattern | Syntax | Truly Private? | Notes |
|---|---|---|---|
| Underscore convention | _field | No | Just a naming hint, still accessible |
| Closure variable | let field in IIFE | Yes | Works pre-ES2022, but awkward with classes |
| Private class field | #field | Yes | Language-enforced, modern and preferred |
Knowledge Check
1. What does the new keyword do when used with a constructor function?
2. Where do shared methods belong in the constructor function pattern?
3. What is the prototype chain?
4. What does the constructor method in a class do?
5. How is a static method different from an instance method?
6. What must you call inside a subclass constructor before accessing this?
7. How do you declare a private field in an ES2022 class?