10
function A() {}
A.prototype.x = 10;

var a = new A();
alert(a.x); // 10

A.prototype = {
  x: 20,
  y: 30
};

alert(a.y) // undefined
  1. Why does it delegate to old prototype of a.x and not the newer one?
  2. Why is a.y throwing undefined through it is set in prototype?
Shane
  • 5,517
  • 15
  • 49
  • 79
  • 2
    Because `a` was created from the old prototype. It's linked to the prototype object, not to `A`, so the assignment doesn't change anything. See also [here](https://stackoverflow.com/questions/14568239/javascriptinstanceof-operator) or [there](https://stackoverflow.com/questions/17474390/defining-a-javascript-prototype) – Bergi May 24 '15 at 21:23

3 Answers3

11

This is happening because of when you've set A.prototype = obj

Rather than adding properties to the Object which is being inherited by a, you've created an entirely new object as A.prototype and this one isn't being inherited by a

Consider,

function A() {}
A.prototype.x = 10;

var p1 = A.prototype; // keep reference to this

var a = new A();

A.prototype = {x: 20, y: 30};

Object.getPrototypeOf(a) === A.prototype; // false, not the new prototype
Object.getPrototypeOf(a) === p1; // true, the old prototype

// however
var b = new A();
Object.getPrototypeOf(b) === A.prototype; // true, this is the new prototype

If you had made the changes to properties on the old prototype (which I called p1) these would have been seen inherited by a

Paul S.
  • 64,864
  • 9
  • 122
  • 138
  • Its not that we can't change... __proto__ references the old prototype through which we can change it to reference the newer one. – Thalaivar May 24 '15 at 21:28
  • @Thalaivar it's not good practice to use `obj.__proto__` and it's very costly to use `Object.setPrototypeOf`, if you're expecting to need to do these kinds of things, either start off with a longer prototype chain with an empty one you can modify, or separate your code to use multiple constructors. – Paul S. May 24 '15 at 21:39
  • Your answer is crisp and clear, but as you know in JavaScript there is no deadlock situation, there is always a workaround though sometimes costly like you have mentioned. Cheers :) – Thalaivar May 24 '15 at 21:45
2

You just created a new prototype object for the class "A", the old instance of the A

var a = new A();

...did copy the existing prototype object reference for it's instance. That old prototype -object is object of it's own and it is not destroyed because the instance of "A" is holding that reference.

If you want the "y" to be defined, you have to create the object again using new, the new instance would use the object you assinged for the prototype - and that instance has the "y" defined.

http://jsfiddle.net/ejseLum9/

Tero Tolonen
  • 4,144
  • 4
  • 27
  • 32
2

Why does it delegate to old prototype of a.x and not the newer one? Why is a.y throwing undefined through it is set in prototype?

You have created an entirely new prototype object. objects created already before the prototype property was changed will have the old reference and new objects will have new prototype.

// was before changing of A.prototype
a.[[Prototype]] ----> Prototype <---- A.prototype

// became after
A.prototype ----> New prototype // new objects will have this prototype
a.[[Prototype]] ----> Prototype // it will still reference to old prototype

The thumb rule is, prototype is set the moment of object's creation and later on you cannot change. It is possible only to add new or modify existing properties of the object’s prototype.

However, you can make a workaround with __proto__ property.

function A() {}
A.prototype.x = 10;

var a = new A();
alert(a.x); // 10

var _newPrototype = {
  x: 20,
  y: 30
};
A.prototype = _newPrototype; //will fail
alert(a.y) // undefined

A.__proto__ = _newPrototype; //will work
alert(a.x);
alert(a.y);
Thalaivar
  • 23,282
  • 5
  • 60
  • 71