Search code examples
javascriptinheritanceprototype-programming

Prototype object can be changed from instance


Could someone explain this to me in a sensible way:

function One() {}

One.prototype.obj = { key: 'value' };
One.prototype.str = 'string';

var inst1 = new One(),
    inst2 = new One();

// now let’s change some things in our second instance

inst2.obj.key = 'buh!';
inst2.str = 'buh!';

// ok, so what happens to our other instance?

console.log( inst1.str ); // Yields 'string' (unaffected, expected)
console.log( inst1.obj.key ); // Yields 'buh!' (!!)

console.log( One.prototype.obj.key ); // is also 'buh!'

It seems that if a prototype contains an object, the instance you create using the new keyword has that object, but if you change it, you also change the prototype object, thus affecting all instances, like a sibling-inheritance-pattern...

Is this the way it’s suppose to work?


Solution

  • Actually, Javascript doesn't copy anything from the prototype. Everything you define on the prototype exists only once (on the prototype itself) and gets reused because the same prototype instance is passed to all objects.

    When you access a property on an object, the object checks to see if it is defined on itself. If it is, it will return the value associated with that property. If it's not, it will delegate the call to its prototype, who will from now on be responsible for what happens. That's why "inheritance" (code reuse) in Javascript is better called delegation.

    Things are a bit different for write access. If you set a property on the object, it will "shadow" the value locally. That's the reason why the str property is unaffected, it has actually been defined on the inst2 object. But if you delete inst2.str and do another console.log( inst2.str ) you will notice that it will return the old value.

    PS: If you want a way to prevent that from happening have a look at this tutorial: http://kevlindev.com/tutorials/javascript/inheritance/index.htm

    I recommend reading the entire thing, but if you just want the meat see the KevLinDev.extend function in the "Creating a subclass" section.