7

I created 2 instances of a prototype, changed a function in prototype, changes reflected in both the instances (Great). However, when I modified the prototype by removing the function, the function still existed for the existing instances.

function A() {
  this.name = "cool";
}

A.prototype = {
  howCool: function() {
    return this.name + "er";
  }
};

var a1 = new A(),
  a2 = new A();

a1.name = "hot";
//line1
console.log(a1.howCool());
//line2
console.log(a2.howCool());

A.prototype = {};

//line3
console.log(a1.howCool());

//line4
var a3 = new A();
console.log(a3.howCool());

Line 1 and 2 are working as expected and after setting the protoype back to empty, line 4 is showing undefined which is expected. line 3 however is still showing the function definition.

4
  • 6
    You're not modifying the prototype object, you're creating a new one. Commented May 3, 2017 at 16:12
  • See also the same confusion with instanceof and how to properly define a Javascript prototype Commented May 3, 2017 at 16:15
  • 2
    You actually reassigned prototype property to a new object. The old one still exists. Commented May 3, 2017 at 16:15
  • 1
    FWIW, the reason why it doesn't work this way is the same as why after var a = 42; var b = a; a = 21;, b still has the value 42: JavaScript as copy/assign by value semantics. b has a copy of the value of a, not a reference to variable a itself. Similar with prototype, new instances get a copy of the value of A.prototype (which is a reference to an object), not a reference to the property A.prototype itself. Commented May 3, 2017 at 17:11

4 Answers 4

5

Essentially you're reassigning the prototype property for the function A to point to a new object. This does not affect the old object and thus doesn't affect prior instances.

Here's an illustration of what is happening.

After this code executes:

function A() {
  this.name = "cool";
}

A.prototype = {
  howCool: function() {
    return this.name + "er";
  }
};

var a1 = new A(),
  a2 = new A();

the situation is the following:

before

Then after this code executes:

A.prototype = {};

var a3 = new A();

The A.prototype points to a new object but the [[Prototype]] property for old instances still points to the old object.

after

If you want to actually remove the method, you must edit the original object, not point to a new one.

To actually remove howCool() method from the prototype, something like this would work:

delete A.prototype.howCool

Which would give:

finally

Now any future instances, such as a3, and the prior ones, would all still point to the same object but that object won't have the howCool() method.

Sign up to request clarification or add additional context in comments.

Comments

1

Well if you modify the prototype it will affect the old instances, but if you create a new one it won't affect old instances.

So when you write:

A.prototype = {};
//line3
console.log(a1.howCool);

The object a1.__proto__ still points to the initial A.prototype, that's why it doesn't log undefined.

And then when you write :

//line4
var a3 = new A();
console.log(a3.howCool());

The new instance a3 is using the new created A.prototype that's why you got ùndefined`.

Comments

0

Try using the delete operator

function A(){
    this.name = "cool";
}

A.prototype = {
    howCool : function(){
        return this.name + "er";
    }
};

var a1 = new A(),
    a2 = new A();

a1.name = "hot";
//line1
console.log(a1.howCool);
//line2
console.log(a2.howCool);

delete A.prototype.howCool;

//line3
console.log(a1.howCool);

//line4
var a3 = new A();
console.log(a3.howCool);

1 Comment

Or the A.prototype.howCool = undefined;.
0

Here is the possible explanation:
(Note: Below explanation is only for experiments and conceptual understanding as usage of __proto__ should be avoided in production code)

As you know that there is a link between an object(in this case a1) and the prototype of the constructor function( in this case A) out of which object is created. This link is called __proto__ or dunder proto. So in this case it can be seen as a1.__proto__.

Now, what is happening is that when you say A.prototype = {};, at this time object a1 has already been constructed and it is pointing to A.prototype via this link.

Since Javascript is garbage collected language, merely setting A.prototype to {} isn't cleaning up the old protoytpe object right then and hence the older object is still lingering around. So when you say console.log(a1.howCool());, howCool is located in the lingering object.

So, if you modify your line3 like this:

//line3

console.log(a1.__proto__);
a1.__proto__ = {};
console.log(a1.howCool());

You would be able to see older prototype object and howCool() inside it in the console window in the line console.log(a1.__proto__); However, if you set a1.__proto__ = {}; then console.log(a1.howCool()); will not be able to locate the object and howCool() would not be found(as it is now set to empty object).

So just setting A.prototype to {} isn't achieving the same effect as a.__proto__ = {}.

Hence the output that you see.

Hope it helps.

4 Comments

Please don't use __proto__, it's deprecated and creates wrong impressions. Use the standard Object.getPrototypeOf.
@Bergi Sure, I am not intending to use it. This is just to explain the reasoning behind the behavior OP is seeing. I just didn't want to confuse him with additional details. It is easier for him to see this property on a1 object in the console window.
Except that it isn't an actual property, therefore confusing imo.
@Bergi Yes, you are absolutely right! However, I hope larger cause of explaining what is happening is not lost due to this usage. This is in no way meant to be written in production code, just for exploring and experimentation.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.