Skip to main content

Function Prototype

Prototypes / Inheritance: The Prototype Property



What is the prototype property in JavaScript?

View Answer:
Interview Response: In simple terms, the prototype is a regular property in a function or object. Every Object in JavaScript contains the prototype meaning a regular property with the prototype name.

Code Example:

let animal = {
eats: true,
};

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

Rabbit.prototype = animal; // references animal

let rabbit = new Rabbit('White Rabbit'); // rabbit.__proto__ == animal

console.log(rabbit.eats); // true

Can you explain how the prototype property works in JavaScript?

View Answer:
Interview Response: Every function has the "prototype” property even if we do not supply it. The prototype object is a special type of enumerable object to which additional properties can be attached to and shared across all the instances of its constructor function. A function prototype property only gets used when a new Function gets called, and it assigns the prototype of the new object.

Technical Response: Even if we don't offer it, every function has the "prototype" attribute. When a new Function gets invoked, the function prototype property assigns the [[Prototype]] to the new object. After the function prototype property changes (func.prototype = {another object}), new objects generated by the new Function gets another object as [[Prototype]], while existing objects retains the previous one. A default prototype is an object with the sole constructor pointing back to the function itself.

Code Example:

function Rabbit() {}
// by default:
// Rabbit.prototype = { constructor: Rabbit }

let rabbit = new Rabbit(); // inherits from {constructor: Rabbit}

console.log(rabbit.constructor == Rabbit); // true (from prototype)

What happens when you replace the default prototype in JavaScript?

View Answer:
Interview Response: When you override the default prototype in an object, we lose access to the function constructor property of the prototype.

Code Example:

function Rabbit() {}
Rabbit.prototype = {
jumps: true,
};

let rabbit = new Rabbit();
console.log(rabbit.constructor === Rabbit); // false

function Dog() {}

let dog = new Dog();
console.log(dog.constructor === Dog); // true

What is the difference between "proto" and prototype?

View Answer:
Interview Response: `__proto__` is an object's actual prototype, while prototype is the blueprint for what will be assigned to `__proto__` when a new object is created.

Code Example:

First let's clarify the concepts.

In JavaScript, each object has a __proto__ property which is an internal reference to the prototype object from which the instance object inherited. The prototype object is special type of enumerable object to which additional properties can be attached to it which will be shared across all the instances of its constructor function.

Here's an example that showcases the difference:

function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

Person.prototype.getFullName = function() {
return this.firstName + ' ' + this.lastName;
}

let john = new Person('John', 'Doe');

console.log(john.__proto__); // This will output the prototype object of the "john" instance
console.log(Person.prototype); // This will output the prototype object of the "Person" constructor function

console.log(john.__proto__ === Person.prototype); // This will output true, meaning both refer to the same object

console.log(john.getFullName()); // Output: John Doe. This is because "getFullName" method is defined in Person's prototype, so it's accessible to "john" instance.

In this example, you can see that john.__proto__ and Person.prototype both refer to the same object. This is because john was created with the Person constructor, so its prototype (__proto__) is the same as Person.prototype.

The getFullName method is defined on Person.prototype, meaning it's not directly attached to john object. However, it's still accessible to john because john's __proto__ points to Person.prototype.


danger

Note: The __proto__ property is considered deprecated and non-standard. It's better to use Object.getPrototypeOf(object) method to get the prototype of an object.


How does prototypal inheritance work in JavaScript?

View Answer:
Interview Response: In JavaScript, each object has a prototype from which it can inherit properties or methods. A chain of these is called the prototype chain.

What is the purpose of the Object.prototype property?

View Answer:
Interview Response: Object.prototype forms the end of the prototype chain. It's the prototype from which all objects inherit methods and properties.

Can you modify the prototype of an existing object?

View Answer:
Interview Response: Yes, you can modify the prototype of an existing object in JavaScript. But it's not recommended due to performance implications. The `Object.setPrototypeOf()` method is used to set the prototype (i.e., the internal [[Prototype]] property) of a specified object to another object or null.

Code Example:

let animal = {
speaks: true
};

let dog = {
bark: function() {
return 'Woof!';
}
};

// dog is an ordinary object, it doesn't have the 'speaks' property
console.log(dog.speaks); // undefined

// Set animal to be the prototype of dog
Object.setPrototypeOf(dog, animal);

// Now dog has 'speaks' property from its prototype chain
console.log(dog.speaks); // true

// dog can also access the 'bark' method that's directly on it.
console.log(dog.bark()); // 'Woof!'

In this code, dog doesn't initially have a speaks property. When animal is set as the prototype of dog, the dog object can then access animal's speaks property.


danger

Note: While it's possible to change the [[Prototype]] of an object, it's considered a bad practice in production code because it can lead to performance problems. In general, it's better to create the right prototype chain when creating objects. This method is there for completeness and should be used sparingly, if at all.


What happens if you look for a property or a method that's not present in the object but exists in the prototype chain?

View Answer:
Interview Response: The JavaScript engine will look up the prototype chain until it finds the property/method or reaches Object.prototype which will return undefined.

Technical Response: In JavaScript, when you try to access a property or method that doesn't exist in an object, JavaScript will look up the prototype chain to see if it can find it there. If the property or method is found in the prototype chain, it will be returned. If not, `undefined` will be returned.

Code Example:

let animal = {
speaks: true,
sound: function() {
return 'Generic animal sound!';
}
};

let dog = Object.create(animal); // animal is the prototype of dog

dog.bark = function() {
return 'Woof!';
};

console.log(dog.bark()); // 'Woof!', since 'bark' method exists directly on the 'dog' object
console.log(dog.speaks); // true, 'speaks' property doesn't exist directly on the 'dog', but exists in the prototype chain (in 'animal')
console.log(dog.sound()); // 'Generic animal sound!', 'sound' method doesn't exist directly on the 'dog', but exists in the prototype chain (in 'animal')
console.log(dog.meow); // undefined, 'meow' neither exists directly on the 'dog' nor in the prototype chain

In this example, when we call dog.speaks or dog.sound(), JavaScript first checks if these properties/methods exist directly on the dog object. Since they don't, JavaScript then checks dog's prototype, which is animal. Since animal has the speaks property and sound method, these values are returned.

However, when we try to access dog.meow, JavaScript first checks the dog object, and then its prototype animal. Since neither has a meow property, undefined is returned.


What is a prototype chain?

View Answer:
Interview Response: A prototype chain is a succession of links from one object's prototype to another, used when looking for a property or method.

What is the role of the constructor property?

View Answer:
Interview Response: The `constructor` property returns a reference to the `Object` constructor function that created the instance object. Note that this property is derived from the object's prototype.

Code Example:

function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

let john = new Person('John', 'Doe');

console.log(john.constructor); // [Function: Person]

In this code, john.constructor is Person, which is the function used to create john.

The constructor property is also useful when you want to create a new instance and you only have an instance of the object, but not the original constructor. Here's an example:

function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

let john = new Person('John', 'Doe');
let jane = new john.constructor('Jane', 'Doe');

console.log(jane.firstName); // Output: Jane
console.log(jane.lastName); // Output: Doe

Here, john.constructor refers to the Person function, which we can use to create a new Person.


note

Note that the constructor property can be overridden, so it's not a completely reliable way to determine the constructor of an object. The instanceof operator is generally a better choice for that.


What's the difference between prototypal and classical inheritance?

View Answer:
Interview Response: Prototypal inheritance uses instances as prototypes, while classical inheritance uses classes and creates hierarchy through "is-a" relationships.

Technical Response: Prototypal Inheritance (JavaScript-style) and Classical Inheritance (like in Java or C++) are two different ways of dealing with object-oriented code. JavaScript uses prototypal inheritance, but it can mimic classical inheritance with constructor functions and the `new` keyword.

Code Example:

Let's see an example of both:

Classical Inheritance (Simulation in JavaScript)

// Constructor for Superclass
function Animal(name) {
this.name = name;
}

Animal.prototype.speak = function() {
return this.name + ' makes a sound.';
}

// Constructor for Subclass
function Dog(name) {
Animal.call(this, name); // Call the parent's constructor
}

// Establish the prototype chain to inherit methods
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // Repair the constructor reference

Dog.prototype.bark = function() {
return this.name + ' barks.';
}

var dog = new Dog('Rex');
console.log(dog.speak()); // Output: Rex makes a sound.
console.log(dog.bark()); // Output: Rex barks.

In this example, we simulate classical inheritance using constructor functions. Dog is a subclass of Animal and inherits its methods.

Prototypal Inheritance

var animal = {
init: function(name) {
this.name = name;
},
speak: function() {
return this.name + ' makes a sound.';
}
};

var dog = Object.create(animal);
dog.bark = function() {
return this.name + ' barks.';
}

var rex = Object.create(dog);
rex.init('Rex');
console.log(rex.speak()); // Output: Rex makes a sound.
console.log(rex.bark()); // Output: Rex barks.

In this prototypal inheritance example, we directly create objects from other objects. rex is an object created from dog, which is created from animal. The methods from animal are available to dog and rex through the prototype chain.

In prototypal inheritance, an object can directly inherit from another object. This is different from classical inheritance where classes inherit from classes.


What are some common pitfalls with prototypes and inheritance in JavaScript?

View Answer:
Interview Response: Pitfalls include performance issues with changing prototypes, accidental sharing of properties, and confusion with this in prototype methods.

What is the prototype property used for?

View Answer:
Interview Response: It's used to implement object inheritance, to share properties and methods across instances, reducing memory usage.

Do all objects in JavaScript have a prototype?

View Answer:
Interview Response: Almost all objects in JavaScript have a prototype. The root object in the prototype chain is typically Object.prototype, which has null as its prototype.

Here's a code example demonstrating that:

let obj = {};
console.log(obj.__proto__ === Object.prototype); // true

function Func() {}
console.log(Func.__proto__ === Function.prototype); // true

let arr = [];
console.log(arr.__proto__ === Array.prototype); // true

In this code, obj is an object literal, so its prototype is Object.prototype. Func is a function, so its prototype is Function.prototype. arr is an array, so its prototype is Array.prototype.

However, it's possible to create an object without a prototype using Object.create(null). Such objects do not inherit anything, including basic methods like toString():

let noProto = Object.create(null);
console.log(noProto.__proto__); // undefined

In this code, noProto does not have a prototype, so noProto.__proto__ is undefined. Attempting to call toString() on noProto would result in an error.


What is shadowing in JavaScript with regards to prototypes?

View Answer:
Interview Response: Shadowing (also known as method overriding) in JavaScript occurs when a property in an object's prototype chain has the same name as a property in the object itself. In such a case, the object's property "shadows" the property in the prototype.

Code Example:

let animal = {
speak: function() {
return 'The animal makes a sound!';
}
};

let dog = Object.create(animal);

dog.speak = function() {
return 'The dog barks!';
};

console.log(dog.speak()); // Output: The dog barks!

In this code, dog is created with animal as its prototype. animal has a speak method, and dog also has a speak method. When dog.speak() is called, JavaScript first looks for a speak method on the dog object. Since it finds one, it uses that method and does not continue looking up the prototype chain.

If the speak method is deleted from dog, then the speak method from animal is used instead:

delete dog.speak;

console.log(dog.speak()); // Output: The animal makes a sound!

In this code, after the speak method is deleted from dog, dog.speak() outputs 'The animal makes a sound!'. This is because JavaScript doesn't find a speak method on dog, so it looks up the prototype chain and finds the speak method on animal.


Can you remove properties from a prototype?

View Answer:
Interview Response: Yes, you can remove properties from a prototype in JavaScript using the `delete` keyword, which can delete properties from any object. However, you should be careful when doing this, as it can affect all objects that inherit from the prototype.

Code Example:

function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

Person.prototype.getFullName = function() {
return this.firstName + ' ' + this.lastName;
}

let john = new Person('John', 'Doe');

console.log(john.getFullName()); // Output: John Doe

// Deleting property from prototype
delete Person.prototype.getFullName;

console.log(john.getFullName); // Output: undefined

In this example, john.getFullName() initially outputs 'John Doe'. After getFullName is deleted from Person.prototype, john.getFullName is undefined.

While it's possible to delete properties from a prototype, it's generally not a good idea because it can have unexpected side effects. For example, if other code is depending on that property being present in the prototype, that code could stop working correctly.


Can we use arrow functions for prototype methods?

View Answer:
Interview Response: It's possible, but not recommended due to "this" scope issues. Arrow functions don't have their own "this".

Technical Response: While you can technically use arrow functions as prototype methods in JavaScript, it's generally not a good idea because arrow functions behave differently than traditional functions. Specifically, arrow functions don't have their own `this` context, but instead inherit `this` from the surrounding (parent) scope at the time of definition.

Consider the following code example:

function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

Person.prototype.getFullName = () => {
return this.firstName + ' ' + this.lastName;
}

let john = new Person('John', 'Doe');

console.log(john.getFullName()); // Output: undefined undefined

In this case, the getFullName method is an arrow function, so this doesn't refer to the john object. Instead, it refers to the surrounding scope, which in a non-strict global context is the window object (or global object in Node.js environment). Since window.firstName and window.lastName are not defined, john.getFullName() returns "undefined undefined".

Compare this with a traditional function:

Person.prototype.getFullName = function() {
return this.firstName + ' ' + this.lastName;
}

console.log(john.getFullName()); // Output: John Doe

In this case, the getFullName method is a traditional function, so this refers to the john object. john.getFullName() therefore correctly returns "John Doe".

For this reason, arrow functions are generally not used as object methods when those methods need to access other properties of the object.


Why do we say JavaScript has a dynamic prototype?

View Answer:
Interview Response: Because you can add or remove properties and methods even after the object is created.

How does the JavaScript engine find a property in a prototype chain?

View Answer:
Interview Response: It looks from the object up through the prototype chain until it finds the property or reaches Object.prototype.

What is the difference between a prototype and an instance in JavaScript?

View Answer:
Interview Response: In JavaScript, an instance is an object that's created from a constructor function using the `new` keyword. The prototype is an object that is used as a blueprint for creating new objects (instances).

Code Example:

// Define a constructor function
function Car(make, model) {
this.make = make;
this.model = model;
}

// Add a method to the prototype
Car.prototype.displayCar = function() {
return this.make + ' ' + this.model;
}

// Create a new instance of Car
let myCar = new Car('Toyota', 'Corolla');

console.log(myCar.displayCar()); // Outputs: Toyota Corolla

In this code:

  • Car is a constructor function. It defines a blueprint for creating new car objects.
  • Car.prototype.displayCar is a method added to the prototype of Car. This method will be shared by all instances of Car.
  • myCar is an instance of Car. It's an object created from the Car constructor, and it has access to properties and methods defined in the Car constructor and the Car prototype.

So the main difference is that an instance is an individual object created from a constructor, while a prototype is an object that serves as a blueprint for instances. Changes to the prototype affect all instances, while changes to an instance only affect that instance.


What is the default prototype of an object created using an object literal?

View Answer:
Interview Response: The default prototype of an object created using an object literal in JavaScript is `Object.prototype`.

What is Object.create() and how does it relate to prototypes?

View Answer:
Interview Response: `Object.create()` is a static method in JavaScript that creates a new object with the specified prototype object and properties.

Here's how it works in relation to prototypes:

let animal = {
speaks: true,
sound: function() {
return 'Generic animal sound!';
}
};

let dog = Object.create(animal);

dog.bark = function() {
return 'Woof!';
};

console.log(dog.speaks); // true, inherited from 'animal' via prototype chain
console.log(dog.sound()); // 'Generic animal sound!', inherited from 'animal' via prototype chain
console.log(dog.bark()); // 'Woof!', present directly on 'dog'

In this example, animal is used as a prototype for creating dog with Object.create(). As a result, dog has access to the speaks property and the sound method via the prototype chain, while also having its own bark method directly on it.