JavaScript > Prototypes and Inheritance > Constructor Functions and Classes > Static methods and properties
JavaScript Prototypes, Inheritance, and Static Members
This code snippet demonstrates prototypes and inheritance in JavaScript using constructor functions and classes, along with static methods and properties. It illustrates how objects inherit properties and methods from their prototypes and how static members are associated with the class itself rather than instances of the class.
Prototypes and Inheritance
This section showcases inheritance using constructor functions and prototypes. The `Animal` function is a constructor for creating animal objects. The `Dog` function extends `Animal` by calling `Animal.call(this, name)` to inherit the `name` property. Then, we set `Dog.prototype` to a new object created from `Animal.prototype`, establishing the inheritance link. Finally, we reset the `Dog.prototype.constructor` to `Dog` to maintain proper constructor identification. The code then demonstrates creating instances of both `Animal` and `Dog` and calling their respective methods, illustrating how `Dog` instances inherit the `sayHello` method from `Animal`.
function Animal(name) {
this.name = name;
}
Animal.prototype.sayHello = function() {
return `Hello, I'm ${this.name}`;
};
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
return 'Woof!';
};
const animal = new Animal('Generic Animal');
const dog = new Dog('Buddy', 'Golden Retriever');
console.log(animal.sayHello()); // Output: Hello, I'm Generic Animal
console.log(dog.sayHello()); // Output: Hello, I'm Buddy
console.log(dog.bark()); // Output: Woof!
console.log(animal instanceof Animal); // Output: true
console.log(dog instanceof Animal); // Output: true
console.log(dog instanceof Dog); // Output: true
Constructor Functions and Classes
This section demonstrates the same inheritance pattern using ES6 classes. The `AnimalClass` is defined using the `class` keyword, with a constructor and a `sayHello` method. The `DogClass` extends `AnimalClass` using the `extends` keyword and calls `super(name)` in its constructor to invoke the parent class's constructor. This provides a more readable and concise syntax for achieving the same prototypal inheritance as in the previous example. The output is identical, showing that classes are syntactical sugar over the prototype-based inheritance.
class AnimalClass {
constructor(name) {
this.name = name;
}
sayHello() {
return `Hello, I'm ${this.name}`;
}
}
class DogClass extends AnimalClass {
constructor(name, breed) {
super(name);
this.breed = breed;
}
bark() {
return 'Woof!';
}
}
const animalClass = new AnimalClass('Generic Animal');
const dogClass = new DogClass('Buddy', 'Golden Retriever');
console.log(animalClass.sayHello()); // Output: Hello, I'm Generic Animal
console.log(dogClass.sayHello()); // Output: Hello, I'm Buddy
console.log(dogClass.bark()); // Output: Woof!
console.log(animalClass instanceof AnimalClass); // Output: true
console.log(dogClass instanceof AnimalClass); // Output: true
console.log(dogClass instanceof DogClass); // Output: true
Static Methods and Properties
This section demonstrates static methods and properties. Static members are associated with the class itself rather than with instances of the class. `MathUtils.PI` is a static property that holds the value of PI. `MathUtils.calculateCircleArea` is a static method that calculates the area of a circle. You access static members directly through the class name (e.g., `MathUtils.PI`) without creating an instance of the class. Static methods are useful for utility functions or properties that relate to the class as a whole.
class MathUtils {
static PI = 3.14159;
static calculateCircleArea(radius) {
return MathUtils.PI * radius * radius;
}
}
console.log(MathUtils.PI); // Output: 3.14159
console.log(MathUtils.calculateCircleArea(5)); // Output: 78.53975
Concepts Behind the Snippet
new
keyword, a new object is created, and the constructor function is called with this
bound to the new object.
Real-Life Use Case
Imagine you're building a game. You might have a base class called `GameObject` with properties like `x`, `y`, and `width`. Then, you could create subclasses like `Player`, `Enemy`, and `Projectile` that inherit from `GameObject` and add their own specific properties and methods. Static methods could be used for utility functions like calculating distances between objects or checking for collisions.
Best Practices
Interview Tip
Be prepared to explain the difference between prototype-based inheritance and classical inheritance. Understand how to create inheritance relationships using both constructor functions and ES6 classes. Know when and why to use static methods and properties.
When to Use Them
Memory Footprint
Prototypes promote memory efficiency because methods defined on the prototype are shared by all instances of the class. Static members also have a relatively low memory footprint since they are stored only once per class, not per instance.
Alternatives
Pros
Cons
FAQ
-
What is the difference between `prototype` and `__proto__`?
prototype
is a property of constructor functions. It is the object that will become the prototype of objects created using that constructor.__proto__
(deprecated in favor of `Object.getPrototypeOf` and `Object.setPrototypeOf`) is a property of instances that points to the prototype object from which the instance inherits. -
What is the 'this' keyword in JavaScript?
Thethis
keyword refers to the current execution context. In a constructor function,this
refers to the newly created object. In a method of an object,this
refers to the object itself. -
Can I inherit from multiple classes in JavaScript?
JavaScript does not support multiple inheritance in the traditional sense. However, you can achieve similar results using composition or mixins.