Skip to content

Latest commit

 

History

History
164 lines (119 loc) · 5.55 KB

File metadata and controls

164 lines (119 loc) · 5.55 KB

JavaScript prototypes are a mechanism for object inheritance and sharing properties.

Think of it like this: Every object in JavaScript has a hidden link to another object called its prototype. When you try to access a property on an object, JavaScript first looks at the object itself. If it doesn't find the property there, it follows the prototype link and looks in the prototype object, and so on, up the prototype chain.

Key Concepts:

  • Prototype Property: Functions in JavaScript have a special property called prototype. This is an object that will become the prototype for all objects created using that function as a constructor (with the new keyword).
  • __proto__ (Internal Property): Every object (except the very first in the chain) has an internal property [[Prototype]], often accessible as __proto__ in many environments. This points to its prototype object.
  • Prototype Chain: The sequence of prototype objects linked together. This chain continues until it reaches null. If a property isn't found in the object itself or any of its prototypes up the chain, JavaScript returns undefined.
  • Inheritance: Objects inherit properties and methods from their prototype. This avoids code duplication and promotes reusability.

Concise Example:

function Dog(name) {
  this.name = name;
}

// Add a method to the Dog prototype
Dog.prototype.bark = function() {
  console.log("Woof!");
};

let myDog = new Dog("Buddy");
myDog.bark(); // Output: Woof!

console.log(myDog.__proto__ === Dog.prototype); // Output: true

In essence: Prototypes enable objects to inherit features from other objects, forming a chain for property lookup and efficient code sharing.

Key Concepts:

  • prototype (Function Property): Functions have a prototype property, which is an object that becomes the prototype for objects created using that function with new.
  • __proto__ (Object Property): Every object (except the very first in the chain) has an internal [[Prototype]] property (often accessible as __proto__) pointing to its prototype object.
  • Prototype Chain: The linked sequence of prototype objects.

Examples:

// Constructor function
function Animal(sound) {
  this.sound = sound;
}

// Method added to the Animal prototype
Animal.prototype.makeSound = function() {
  console.log(this.sound);
};

// Creating an object
let dog = new Animal("Woof!");
dog.makeSound(); // Output: Woof!

// Accessing the prototype
console.log(dog.__proto__ === Animal.prototype); // Output: true

// Inheritance
function Dog(name) {
  this.name = name;
  Animal.call(this, "Bark!"); // Call Animal constructor
}

// Set up prototype chain: Dog inherits from Animal
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // Reset constructor

let buddy = new Dog("Buddy");
buddy.makeSound(); // Output: Bark! (inherited)
console.log(buddy instanceof Animal); // Output: true

Key Takeaways:

  • Prototypes are about inheritance and sharing behavior between objects.
  • Types classify the kind of data a variable holds and govern how that data can be manipulated.
  • JavaScript's dynamic typing allows variables to change types during execution.
  • Understanding the distinction between primitive and reference types is crucial for comprehending how values are assigned and compared.

1. Inheritance and Method Sharing:

function Animal(sound) {
  this.sound = sound;
}

Animal.prototype.makeSound = function() {
  console.log(this.sound);
};

function Cat(name) {
  this.name = name;
  Animal.call(this, "Meow"); // Call Animal constructor to initialize 'sound'
}

// Set up the prototype chain: Cat.prototype inherits from Animal.prototype
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat; // Reset the constructor property

Cat.prototype.purr = function() {
  console.log("Purrrr...");
};

let fluffy = new Cat("Fluffy");
fluffy.makeSound(); // Output: Meow
fluffy.purr();     // Output: Purrrr...

console.log(fluffy.__proto__ === Cat.prototype);       // true
console.log(Cat.prototype.__proto__ === Animal.prototype); // true
console.log(fluffy instanceof Animal);                // true
console.log(fluffy instanceof Cat);                   // true

2. Adding Properties to Built-in Prototypes (Use with Caution!):

// Adding a method to the String prototype
String.prototype.reverse = function() {
  return this.split('').reverse().join('');
};

let myString = "hello";
console.log(myString.reverse()); // Output: olleh

// Adding a method to the Array prototype
Array.prototype.last = function() {
  return this[this.length - 1];
};

let myArray = [1, 2, 3];
console.log(myArray.last()); // Output: 3

3. The Prototype Chain in Action:

let obj = {
  propertyA: 'valueA'
};

let protoObj = {
  propertyB: 'valueB',
  methodC: function() {
    console.log("Method C called from protoObj");
  }
};

// Set protoObj as the prototype of obj
Object.setPrototypeOf(obj, protoObj);

console.log(obj.propertyA); // Output: valueA (found directly in obj)
console.log(obj.propertyB); // Output: valueB (found in obj's prototype)
obj.methodC();              // Output: Method C called from protoObj (found in obj's prototype)
console.log(obj.propertyD); // Output: undefined (not found in obj or its prototype)

console.log(obj.__proto__ === protoObj); // Output: true
console.log(protoObj.__proto__ === Object.prototype); // Output: true (default prototype for objects)
console.log(Object.prototype.__proto__); // Output: null (end of the chain)