3

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

let rabbit = new Rabbit();

Rabbit.prototype = {};

alert( rabbit.eats ); // ?
Why rabbit.eat shows true when we set its reference i.e constructor Function prototype Rabbit to empty?

Of what i know that when the compiler reads the statement (rabbit.eat) it first checks in the object whether the property exist or not then it looks in the rabbit.__proto__ i.e the Rabbit.prototype for the property. but here we assign Rabbit.prototype = {} so why the object rabbit still have eat property??

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
Amandeep Saini
  • 898
  • 7
  • 10

2 Answers2

2

The prototype of the instantiated Rabbit, the rabbit, is still the original Rabbit.prototype object, which has eats: true. Reassigning the prototype does not mean that the interpreter goes through every instantiated object and changes the prototype.

If you wanted to change the prototype of an existing object, you can use setPrototypeOf, like this:

function Rabbit() {}
Rabbit.prototype = {
  eats: true
};
let rabbit = new Rabbit();
Rabbit.prototype = {};
Object.setPrototypeOf(rabbit, Rabbit.prototype);
alert(rabbit.eats); // ?

But:

Warning: Changing the [[Prototype]] of an object is, by the nature of how modern JavaScript engines optimize property accesses, a very slow operation, in every browser and JavaScript engine. The effects on performance of altering inheritance are subtle and far-flung, and are not limited to simply the time spent in Object.setPrototypeOf(...) statement, but may extend to any code that has access to any object whose [[Prototype]] has been altered. If you care about performance you should avoid setting the [[Prototype]] of an object. Instead, create a new object with the desired [[Prototype]] using Object.create().

Alternatively, instead of reassigning the prototype, you could mutate the prototype into an empty object:

function Rabbit() {}
Rabbit.prototype = {
  eats: true
};
let rabbit = new Rabbit();

// `for..in` will iterate over all properties, including inherited ones
// if you don't want that, iterate over Object.keys instead
for (const key in Rabbit.prototype) {
  delete Rabbit.prototype[key];
}

console.log(rabbit.eats);

Other mutations to rabbit's original prototype will also change what you can access on rabbit, as long as you aren't reassigning the class's prototype (which creates a separate unlinked object):

function Rabbit() {}
Rabbit.prototype = {
  eats: true
};
let rabbit = new Rabbit();
// mutation, not reassignment
Rabbit.prototype.eats = 'foo';

console.log(rabbit.eats); // ?
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • 1
    If you set `Rabbit.prototype.eats = {};` it does change it, even for the already instantiated Rabbit. Why is that? – baao May 26 '18 at 08:45
  • 1
    Because with that, you're mutating the prototype (the object that `rabbit`'s prototype references) rather than reassigning the prototype to something completely new (which `rabbit`'s prototype *does not reference*) – CertainPerformance May 26 '18 at 08:48
  • Maybe a good addition for the answer too – baao May 26 '18 at 08:49
  • There's a sentence fragment "*When you do*" which – Bergi May 26 '18 at 12:30
0

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

let rabbit = new Rabbit();

Rabbit.prototype = {};

alert( rabbit.eats );

let rabbit2 = new Rabbit();

alert(rabbit2.eats); //This will now say undefined

You are not changing the prototype of the already instantiated object.

Joey Pinto
  • 1,735
  • 1
  • 18
  • 34
  • I'm wondering how this relates to https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes which shows updating the prototype affecting existing instances? – John Hascall May 26 '18 at 08:49