From what I know a function should inherit the properties from its prototype
object, which can be accessed using .prototype
or __proto__
property.
//my prototype Object
var myObj = {
a: 1,
b: 2
};
var myFunc = function () {};
// setting function's `prototype` property
myFunc.prototype = myObj;
alert(myFunc.a);
//returns undefined (Why???) I was expecting 1
But when I tried the following,
//setting function __proto__ property
myFunc.__proto__ = myObj;
//returns 1
alert(myFunc.a);
So why does it work when I set myFunc.__proto__
and not when I set myFunc.prototype
?
I did refer to __proto__ VS. prototype in JavaScript but couldn't figure out.
__proto__
You can actually access the internal [[Prototype]]
property of an object with __proto__
. You can think of [[Prototype]]
as the actual parent of the current object, in the inheritance hierarchy.
prototype
This is a special property, when set on a (constructor) function object, used to establish the inheritance chain for instances created from the constructor. For example,
function Foo() {}
Foo.prototype = {a: 1};
Now, when you create a new object of type Foo
, the newly created object's internal [[Prototype]]
property will refer the Foo.prototype
object. You can confirm that like this
console.assert((new Foo()).__proto__ === Foo.prototype);
In your case,
myFunc.prototype = myObj;
you are creating a prototype
property on the function object and this will be used only when you are creating new objects with this function (constructor function). You might want to think of it as a template for the new objects. So, when you do myFunc.a
, JS engine tries to find a
in myFunc
and its parents in the prototype chain and it doesn't find it, that is why it returns undefined
.
But, when you do
myFunc.__proto__ = myObj;
you are setting the parent of myFunc
, in the prototype chain, to myObj
. So, when you do myFunc.a
, JS engine first tries to find a
in myFunc
object itself, and it is not there. So, it tries to find it in its immediate parent, which is myObj
. That is why it returns 1
in this case.
Note: You can use the following function to understand the prototype chain better
function printPrototypeChain(object) {
while (object !== null) {
console.log(object);
object = Object.getPrototypeOf(object);
}
}
Now, let us print the prototype chain when the object is set as the prototype
property of the function object.
function myFunc() {}
myFunc.prototype = {
a: 1,
b: 2
};
printPrototypeChain(myFunc);
The output will be
[Function: myFunc]
[Function: Empty]
{}
None of these objects have a
defined, so undefined
is returned. But, in this case,
function myFunc() {}
myFunc.__proto__ = {
a: 1,
b: 2
};
printPrototypeChain(myFunc);
the prototype chain becomes like this
[Function: myFunc]
{ a: 1, b: 2 }
{}
and a
is found in myFunc
's immediate parent. So, corresponding value 1
is returned.
Note: Don't use __proto__
in your actual code, as it is retained in the latest versions of JavaScript specification just for backward compatibility. Read more about it here. Use Object.getPrototypeOf
and Object.setPrototypeOf
instead.
You're confusing myFunc
, which is a constructor, with an instance of myFunc
.
If you do something like this:
var o = new myFunc();
alert(o.a);
It will alert 1 because o
is an instance of myFunc
, so its a
property comes from the myFunc
prototype.
If you set __proto__
, you're literally swapping out the Function prototype that myFunc
was inheriting from before and replacing it with your prototype object. In fact, after you do that, any methods you can normally use on functions, such as call
, won't be found on myFunc
anymore.
myFunc.__proto__ = myObj;
myFunc.call(null); // Will throw an error
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With