- JS Introduction
- JS Introduction
- JS Comments
- JS Variables
- JS Datatypes
- JS Operators
- JS Type Conversions
- JS Control Flow
- JS Comparisons
- JS If else
- JS If else Ladder
- JS Ternary Operator
- JS Switch
- JS For Loop
- JS For In
- JS For Of
- JS While
- JS Do While
- JS Break & Continue
- JS Functions
- JS Function Declaration
- JS Function Parameters
- JS Return Statement
- JS Function Expressions
- JS Anonymous Functions
- JS Objects
- JS Objects
- JS Object Methods
- JS Object Constructors
- JS Object Destructuring
- JS Object Prototypes
- JS Map, Filter & Reduce
- JS ES6
- JS ES6
- JS let and const
- JS Arrow Functions
- JS Template Literals
- Destructuring Assignment
- JS Spread Operator
- JS Default Parameters
- JS Classes
- JS Inheritance
- JS Map
- JS Set
- JS Async
- JS Callbacks
- JS Asynchronous
- JS Promises
- JS Async/Await
- JS HTML DOM/BOM
- JS Document Object
- JS getElementbyId
- getElementsByClassName
- JS getElementsByName
- getElementsByTagName
- JS innerHTML
- JS outerHTML
- JS Window Object
- JS History Object
- JS Navigator Object
- JS Screen Object
JavaScript Inheritance
Prototype-based Inheritance:
- JavaScript is unique because it uses prototype-based inheritance. Unlike "classical" languages like Java or C++, JavaScript doesn't actually copy properties from one class to another. Instead, it links objects together. When you try to access a property on an object, JavaScript looks at that object first; if it can't find it there, it "asks" the object's prototype.
- This mechanism allows for efficient memory usage because multiple objects can share a single copy of a method rather than each instance carrying its own copy.
Developer Tip: Even though modern JavaScript uses the
class syntax, it is still just "syntactic sugar" over prototypes. Understanding prototypes is essential for debugging complex inheritance issues.
Prototype Chain:
- Every JavaScript object has a hidden internal property called
[[Prototype]]. In the browser, this is often exposed as__proto__. This reference points to another object, which points to another, and so on. - This sequence is known as the prototype chain. The chain continues until it reaches
Object.prototype, and finallynull, which signals the end of the line.
Watch Out: If you create a very deep prototype chain, property lookups can become slower because the engine has to traverse multiple levels to find a value. Keep your hierarchies flat and logical.
Example: Creating a Parent Object
In this example, we define a base "class" using a constructor function. We attach methods to the prototype so they aren't recreated every time we make a new shape.
function Shape(color) {
// Instance property: unique to every shape
this.color = color;
}
// Prototype method: shared by all shapes
Shape.prototype.getColor = function() {
return this.color;
};
Best Practice: Always define methods on the
prototype rather than inside the constructor function. This saves memory because all instances share the same function reference.
Creating a Child Object (Inheriting from Parent)
To inherit, we need to do two things: link the data (properties) and link the behavior (methods).
function Circle(radius, color) {
// 1. "Borrow" the Parent constructor to set properties
Shape.call(this, color);
this.radius = radius;
}
// 2. Link the prototypes so Circle can use Shape's methods
Circle.prototype = Object.create(Shape.prototype);
// 3. Fix the constructor reference (otherwise it would point to Shape)
Circle.prototype.constructor = Circle;
Circle.prototype.getRadius = function() {
return this.radius;
};
Common Mistake: Forgetting to reset the constructor. If you omit
Circle.prototype.constructor = Circle;, an instance of Circle will report its constructor as Shape, which can break logic that relies on identifying object types.
Instanceof Operator:
- The instanceof operator is a way to check an object's "ancestry." It checks if a specific constructor's prototype appears anywhere in the object's prototype chain.
- This is incredibly useful for writing functions that need to handle different types of objects differently (polymorphism).
Example: Using Instanceof
const circle = new Circle(5, 'red');
// True: it was created by the Circle constructor
console.log(circle instanceof Circle);
// True: it inherits from Shape through the prototype chain
console.log(circle instanceof Shape);
// True: everything (mostly) inherits from Object
console.log(circle instanceof Object);
Developer Tip: In real-world apps, inheritance is great for UI components. You might have a base
Button component and more specific SubmitButton or DeleteButton children that inherit the base styling and click logic.
Key Points
- Delegation, not duplication: Objects delegate property lookups to their prototypes, allowing for powerful code reuse.
- The Constructor Pattern: Use
Parent.call(this, args)to initialize parent properties within a child object. - Object.create: This is the standard way to create a new object using an existing object as its prototype without executing the parent's constructor again.
- The Chain: If a property isn't found on the object, JS searches up the chain until it finds it or hits
null.