Object-Oriented Programming in JavaScript
In this lesson, we’ll explore how JavaScript handles object-oriented programming (OOP) and compare it with Java’s approach. As a Java developer, you’re already familiar with class-based OOP, but JavaScript’s prototypal inheritance model might be new to you. We’ll cover both the traditional prototypal approach and the more recent ES6 class syntax, which should feel more familiar to you.
Prototypal Inheritance vs. Class-based Inheritance
Java uses class-based inheritance, where objects are instances of classes. JavaScript, on the other hand, traditionally uses prototypal inheritance. In this model, objects inherit directly from other objects.
Let’s look at a simple example:
// JavaScript
const animal = {
makeSound: function() {
console.log("Some generic animal sound");
}
};
const dog = Object.create(animal);
dog.bark = function() {
console.log("Woof!");
};
dog.makeSound(); // Outputs: "Some generic animal sound"
dog.bark(); // Outputs: "Woof!"
In this example, dog
inherits from animal
through the prototype chain. This is fundamentally different from Java’s class-based inheritance, where you would define a Dog
class that extends an Animal
class.
ES6 Class Syntax
To make JavaScript more accessible to developers coming from class-based languages like Java, ES6 introduced a class
syntax. This syntax is syntactic sugar over JavaScript’s existing prototype-based inheritance.
Here’s how you might define a class in JavaScript:
// JavaScript
class Animal {
constructor(name) {
this.name = name;
}
makeSound() {
console.log("Some generic animal sound");
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
bark() {
console.log("Woof!");
}
}
const myDog = new Dog("Buddy");
myDog.makeSound(); // Outputs: "Some generic animal sound"
myDog.bark(); // Outputs: "Woof!"
This should look more familiar to you as a Java developer. However, it’s important to understand that under the hood, JavaScript is still using prototypal inheritance.
Constructor Functions and the ‘new’ Keyword
Before the introduction of the class
syntax, JavaScript used constructor functions to create objects. This approach is still valid and widely used:
// JavaScript
function Animal(name) {
this.name = name;
}
Animal.prototype.makeSound = function() {
console.log("Some generic animal sound");
};
function Dog(name) {
Animal.call(this, name);
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
console.log("Woof!");
};
const myDog = new Dog("Buddy");
myDog.makeSound(); // Outputs: "Some generic animal sound"
myDog.bark(); // Outputs: "Woof!"
The new
keyword in JavaScript serves a similar purpose to Java’s new
, but it’s important to note that in JavaScript, it’s used with constructor functions rather than class definitions (even though the class
syntax uses new
as well).
Inheritance Using extends and super
The extends
keyword in JavaScript’s class syntax works similarly to Java:
// JavaScript
class Vehicle {
constructor(wheels) {
this.wheels = wheels;
}
drive() {
console.log(`Driving with ${this.wheels} wheels`);
}
}
class Car extends Vehicle {
constructor(brand) {
super(4);
this.brand = brand;
}
honk() {
console.log(`${this.brand} car honking`);
}
}
const myCar = new Car("Toyota");
myCar.drive(); // Outputs: "Driving with 4 wheels"
myCar.honk(); // Outputs: "Toyota car honking"
The super
keyword is used to call the parent class constructor and to access parent class methods, just like in Java.
Encapsulation and Private Fields
JavaScript has traditionally lacked true private fields, but there have been conventions to simulate privacy. With the recent addition of the #
prefix, JavaScript now supports true private fields:
// JavaScript
class BankAccount {
#balance = 0; // Private field
deposit(amount) {
if (amount > 0) {
this.#balance += amount;
}
}
getBalance() {
return this.#balance;
}
}
const account = new BankAccount();
account.deposit(100);
console.log(account.getBalance()); // Outputs: 100
console.log(account.#balance); // Syntax Error: Private field
This #
syntax for private fields is a recent addition to JavaScript and may not be supported in older environments.
Conclusion
In this lesson, we’ve explored how JavaScript handles object-oriented programming. We’ve seen how its prototypal inheritance model differs from Java’s class-based approach, and how the ES6 class syntax provides a more familiar interface for developers coming from languages like Java. We’ve also looked at constructor functions, inheritance, and the concept of private fields in JavaScript.
In the next lesson, we’ll dive into functional programming concepts in JavaScript, exploring how JavaScript’s treatment of functions as first-class citizens opens up powerful programming paradigms that might be new to you as a Java developer.