0

I thought I mastered prototypal inheritance but now setting object properties on derived objects work. Consider this code:

var com_mtag = {};
com_mtag.start = function(){
// creating myBase and setting a string property and an object-property
    // both have a "prop" property set to "Base"
com_mtag.myBase = {};
com_mtag.myBase.prop = "Base";
com_mtag.myBase.obj = {prop: "Base"};

// Now derive myObj from myBase...
com_mtag.myObj = Object.create(com_mtag.myBase);

    // modifying prop and obj.prop via the derived object
com_mtag.myObj.prop = "Derived";
com_mtag.myObj.obj.prop = "Derived";
};

The result is this: 1) both myBase and myObj have a property "prop" with the values "Base" and "Derived" respectively (as expected) 2) but myBase.obj and myObj.obj point to the same object which now has the value prop="Derived"

How does this work? I've learned that when setting object properties, the interpreter will not go down the prototype chain but create the property on the instance where the "set" was performed (it did this for the string property). But how did the interpreter handle setting the object property? It must have gone down the chain in order to locate the object. And did it create a new reference to this object within the derived object?

Hoping that I made myself clear (which I doubt when I read this but I cannot explain better), I would very much appreciate anyone to shed some light on this.

vkoster
  • 45
  • 8

1 Answers1

1

I've learned that when setting object properties, the interpreter will not go down the prototype chain but create the property on the instance where the "set" was performed

Yes, this is true, but every property in your access chain com_mtag.myObj.obj is reading property values, not setting them. Only the .prop at the end actually sets anything.

When you set a property on an object, you are setting the object's own property (we say "own" property to distinguish them from inherited prototype properties), which shadows any prototype property with the same name. This is why you can shadow the inherited com_mtag.myObj.prop with a new value: com_mtag.myObj gains its own prop property.

However, with com_mtag.myObj.obj.prop, you set the property of an object that exists as a propery of the myBase prototype. In this case, com_mtag.myObj does not gain its own obj propety, because you are not setting obj; you are merely reading it.

com_mtag.myObj doesn't have its own obj property, so com_mtag.myObj.obj must refer to the value stored in the propotype's obj property, i.e., com_mtag.myBase.obj. Therefore, com_mtag.myObj.obj.prop refers to the prop property on that object.

If you had given com_mtag.myObj its own obj property, then com_mtag.myObj.obj.prop would set prop on the value stored in that obj. Since com_mtag.myObj has no such property of its own, it must use the object stored at com_mtag.myBase.obj to find an object to set prop on.

Consider instead the possibility of creating a new object with a prop property, and storing that whole object in com_mtag.myObj.obj:

com_mtag.myObj.obj = { prop: "Derived" };

Without creating a new object like that, only the original prototype obj object exists. The JavaScript engine will not create a new object on myObj.obj; it will use the one on the prototype.

apsillers
  • 112,806
  • 17
  • 235
  • 239
  • Understood. I now created a brand new {prop: "Band New"} and assigned this to com_mtag.myObj.obj. This resulted in com_mtag.myObj now owning its own obj property, referencing the new object. Just as you indicated. Thanks a lot. – vkoster Jun 08 '14 at 22:44