When you did
C.prototype = new B();
You didn't say "whenever you need a prototype, do new B
". What you said is "assign the prototype to new B()
(which shouldn't be very surprising). What you get is:
C.prototype.b.a === 0
Whenever you do new C
, you're not duplicating C.prototype
- you're just linking to it, to the same B
objcet:
C.prototype = new B()
^ ^
| |
c1 c2
c1.b === c2.b; //true
As you may know, objects can be changed to your heart's content. So when you do c1.b.a = 4
, you're going through to the underlying object and messing around with it.
Edit: The first example works because of how the property resolution works. The b
property does not reside on the objects c1
or c2
. When you say "give me c1.b
" the js engine does something like this:
- Is there a
b
property on c1
? Nope, there isn't.
- Let's look at the prototype of
c1
(the actual prototype, what the object got its methods and properties from - in this case, C.prototype
)
- oh yes, it has a
b
property. Return it.
Which, in actual js, is this (spec):
function GetProperty (name, obj) {
while (obj !== null) {
if (obj.hasOwnProperty(name)) {
return obj[name];
}
obj = Object.getPrototypeOf(obj);
}
return undefined;
}
So, in the case that b
is an object, you've got a hold of an object. Changing it changes it like a normal object (do note that you're not assigning to c1.b
directly - you'll see what I mean in a bit). Explained with arrows:
C.prototype.b = 0
^ ^
| |
c1.b c2.b
This is important, so I'll stress it again: When you get a hold on c1.b
, you're getting an object, which is manipulated like any other object. Assigning properties to it is as any other normal object, and mutating it...well, mutates it.
Now, in the former case (c1.b = 10
), you're actually assigning a property. This means you're creating a key/value pairing on the c1
object itself. So, in the first step, we look to see if c1
has a property b
- and it has. Explained with more arrows:
C.prototype.b = 0
^
|
c1.b=10 c2.b
Changing the latter example, we can observe the same effect:
//changing
c1.b.a = 10;
//to
c1.b = 4;
c2.b !== 4 && c2.b.a === 0; //true
To recap:
- In the former example, you simply set a property on the
c1
object.
- In the latter example, you set a property on an object on
c1
s prototype, which mutated it on all other C
objects.