Let's consider the following code,
let f = function () {
this.a = 1;
this.b = 2;
}
let o = new f();
f.prototype.c = 3;
console.log(Object.getPrototypeOf(o));
Prints
[object Object] { c: 3 }
But if I use setPrototypeOf instead of f.prototype.c, the object is empty.
let f = function () {
this.a = 1;
this.b = 2;
}
let o = new f();
Object.setPrototypeOf(f, {c: 3});
console.log(Object.getPrototypeOf(o));
Prints
[object Object] { ... }
But if I use
let f = function () {
this.a = 1;
this.b = 2;
}
let o = new f();
Object.setPrototypeOf(f, {c: 3});
console.log(Object.getPrototypeOf(f));
Prints
[object Object] { c: 3 }
In short the question is, when using Object.setPrototypeOf(o), the Object prints empty, and when using Object.setPrototypeOf(f), the objects prints the property which is added. where as when setting prototype using f.prototype.c = 3, it is accessible by both Objects prototype and the functions prototype.
When you Object.setPrototypeOf(f, ... )
, the chain is actually 3 long:
The prototype of o
is f
. The prototype of f
is {c:3}
.
So your examples are not equivalent to each other:
1)
In the first example, you add the property c
directly to the prototype that instances of f
will use, so the proto of o
contains c
since f
is the constructor for o
.
In the last two examples you add c
to the proto of f
, so the prototype f
was created with. Remember that functions are also just objects and that you're setting the proto of a function you use as a constructor. So the proto of o
contains the proto of f
which contains c
.
2)
In the 2nd example, you getPrototypeOf() o
.
In the 3rd, you getPrototypeOf() f
. Hence only the 3rd example shows c
again.
3)
If you inspect the element in chrome, you see that the constructor of the 2nd example is f
, since you ask the proto of o
.
In the 3rd example you'll see that the constructor is Object
, since you ask the proto of f
, which has been set to the object {c}
and skip the proto from o
to f
.
PS: I'm aware this is might be a confusing explanation.
PPS: If you want inheritance, sticking to child.prototype = Object.create( parent.prototype ); child.constructor = child;
or ES6 class class child extends parent
when it can be used led to the least confusion for me personally.
var first = function first() {
this.value = 'first function';
};
// before .prototype.extra, first inherist from Function.
console.log( 'constructor of first before:', first.constructor );
first.prototype.extra = 'implemented with .prototype.extra';
// after .prototype.extra, first still inherits from Function, we did not change anything to first itself.
console.log( 'constructor of first after:', first.constructor );
// When first is used as a prototype, the instances will get "extra".
// Aka, everything that inherist from first.
var first_instance = new first();
console.log( 'extra on instance of first:', first_instance.extra );
// f itself does NOT have the extra property, only instances of first do.
console.log( 'extra on first itself:', first.extra );
console.log( '------' );
var second = function second() {
this.value = 'second function';
};
// before setPrototypeOf, second inherist from Function, like above.
console.log( 'constructor of second before:', second.constructor );
Object.setPrototypeOf( second, { extra: 'implemented with .setPrototypeOf()' });
// after setPrototypeOf, second inherist from Object, we broke the default inheritance chain.
console.log( 'constructor of second after:', second.constructor );
// BY doing this, we effectively turned second into an object.
// It no longer is a function, so we cannot use function methods like .call() or .apply()
console.log( 'second is object, not function: function.apply', second.apply );
console.log( 'second is object, not function: object.hasOwnProperty', second.hasOwnProperty );
// When second is used as a prototype, the instances will not get "extra".
var second_instance = new second();
console.log( 'extra on instance of second:', second_instance.extra );
// second itself Does have the extra property, sine we assigned it on the prototype used by second. not when second is used as the prototype.
console.log( 'extra on second itself:', second.extra );