Object-Oriented Programming in JavaScript

In this lesson, we’ll explore how JavaScript implements object-oriented programming (OOP) concepts and compare it with Python’s approach. While both languages support OOP, JavaScript’s implementation has some unique characteristics that set it apart from Python’s class-based system.

Prototypal Inheritance vs Class-based Inheritance

JavaScript traditionally uses prototypal inheritance, which is different from Python’s class-based inheritance. In prototypal inheritance, objects inherit directly from other objects. However, to make things more familiar for developers coming from class-based languages, JavaScript introduced the class syntax in ES6.

// JavaScript
// Traditional prototypal approach
function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function () {
  console.log(`${this.name} makes a sound.`);
};

// ES6 class syntax (syntactic sugar over prototypes)
class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a sound.`);
  }
}
# Python
class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        print(f"{self.name} makes a sound.")

While the ES6 class syntax looks similar to Python, it’s important to remember that under the hood, JavaScript is still using prototypal inheritance.

Constructor Functions and the new Keyword

In JavaScript, constructor functions are used to create objects. These are similar to Python’s __init__ method, but with some key differences:

// JavaScript
function Dog(name, breed) {
  this.name = name;
  this.breed = breed;
}

const myDog = new Dog('Buddy', 'Golden Retriever');

The new keyword in JavaScript is crucial here. It creates a new object, sets this to refer to that object within the constructor function, and returns the object. In Python, object creation is handled implicitly when you call the class.

Inheritance with extends and super

JavaScript’s ES6 classes support inheritance using the extends keyword, similar to Python:

// JavaScript
class Dog extends Animal {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }

  speak() {
    console.log(`${this.name} barks.`);
  }
}
# Python
class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)
        self.breed = breed

    def speak(self):
        print(f"{self.name} barks.")

The super keyword in JavaScript, like in Python, is used to call methods on the parent class.

Static Methods and Properties

Both JavaScript and Python support static methods and properties, which belong to the class itself rather than instances of the class:

// JavaScript
class MathOperations {
  static PI = 3.14159;

  static square(x) {
    return x * x;
  }
}

console.log(MathOperations.PI);
console.log(MathOperations.square(4));
# Python
class MathOperations:
    PI = 3.14159

    @staticmethod
    def square(x):
        return x * x

print(MathOperations.PI)
print(MathOperations.square(4))

Encapsulation and Privacy in JavaScript

JavaScript traditionally doesn’t have built-in privacy mechanisms like Python’s convention of using underscores for private attributes. However, there are ways to achieve privacy:

// JavaScript
class BankAccount {
  #balance = 0; // Private field (recent addition to JavaScript)

  deposit(amount) {
    if (amount > 0) {
      this.#balance += amount;
    }
  }

  getBalance() {
    return this.#balance;
  }
}

const account = new BankAccount();
account.deposit(100);
console.log(account.getBalance()); // 100
console.log(account.#balance); // SyntaxError: Private field '#balance' must be declared in an enclosing class

The # prefix for private fields is a recent addition to JavaScript and may not be supported in all environments yet. Before this, developers used closures or symbols to achieve privacy.

Conclusion

While JavaScript’s object-oriented programming model has its roots in prototypal inheritance, the introduction of the class syntax has made it more accessible to developers coming from class-based languages like Python. Though the two languages differ in syntax and terminology, both implement inheritance through runtime delegation along a chain—whether it’s Python’s class hierarchy or JavaScript’s prototype chain. Understanding these similarities and the subtle differences will help you write more effective and idiomatic JavaScript code.

In the next lesson, we’ll explore functional programming features in JavaScript, comparing them with Python’s approach to functional programming. We’ll look at how JavaScript’s first-class functions, higher-order functions, and unique features like the this keyword present both challenges and opportunities for Python developers.