How does __proto__ differ from constructor.prototype?
I've been trying to wrap my head around this recently and finally came up with this "map" that I think sheds full light over the matter
http://i.stack.imgur.com/KFzI3.png
I know I'm not the first one making this up but it was more interesting figuring it out that finding it :-). Anyway, after that I found e.g. this another diagram that I think says basicly the same:
Javascript object layout
The most surprising thing for me was discovering that Object.__proto__
points to Function.prototype
, instead of Object.prototype
, but I'm sure there's a good reason for that :-)
I paste the code mentioned in the image here as well for if anyone wants to test it. Note that some properties are added to the objects for making easy to know where we are after some jumps:
Object.O1='';
Object.prototype.Op1='';
Function.F1 = '';
Function.prototype.Fp1 = '';
Cat = function(){};
Cat.C1 = '';
Cat.prototype.Cp1 = '';
mycat = new Cat();
o = {};
// EDITED: using console.dir now instead of console.log
console.dir(mycat);
console.dir(o);
__proto__ VS. prototype in JavaScript
__proto__
is the actual object that is used in the lookup chain to resolve methods, etc. prototype
is the object that is used to build __proto__
when you create an object with new
:
( new Foo ).__proto__ === Foo.prototype
( new Foo ).prototype === undefined
__proto__ and prototype difference
__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.
Trying to understand the difference between prototype and constructor in JavaScript
It is pretty hard to wrap your mind around this concept if you are used to the ease of extending objects in other OOP languages, but I'll do my best to explain the uses of those and what is what. I am going to assume you are familiar with other OOP languages. Correct me if I'm wrong.
All functions have the prototype Function()
. They are inheriting all base functionality from Function
like toString()
and valueOf()
.
Then there is a constructor. That is what you use to initialize an object with.
p = new Foo();
So in this case we have two things.
- A
function Foo
withFunction
as prototype(Foo) - A
Function
object withFoo()
as constructor(p)
(following me yet?)
The Foo()
constructor can override some base functionality of the Function
constructor or leave it as it is and make good use of it.
If you are familiar with OOP principles, The prototype is the base class, the constructor your current class. In OOP the above would be class Foo extends Function
You can also start inheritance with this entire setup of prototype and constructor making more complex objects as you go whilst sharing functionality.
For example this:
// Make an object initialiser extending Function. In OOP `class Foo extends Function`
function Foo(bar) {
this.baz = bar;
}
Foo.prototype.append = function(what) {
this.baz += " " + what;
};
Foo.prototype.get() {
return this.baz
}
Now lets say we want different ways to get baz
out of there. One for console logging and one for putting it on the title bar.
We could make a big thing about our class Foo
, but we don't do that, because we need to do wholly different things with the new classes that are made for different implementations. The only thing they need to share are the baz
item and the setters and getters.
So we need to extend it to use an OOP term. In OOO this would be the desired end result class Title extends Foo(){}
. So lets take a look at how to get there.
function Title(what) {
this.message = what;
}
At this point the Title
function looks like this:
- prototype Function
- constructor Title
So, to make it extends Foo
we need to change the prototype.
Title.prototype = new Foo();
- prototype Foo
- constructor Foo
This is done by initializing a new Foo()
object against the prototype.
Now its basically a Foo
object called Title
. That is not what we want because now we can't access the message part in Title
.
We can make it properly extend Foo()
by resetting the constructor to Title
Title.prototype.constructor = Title;
- prototype Foo
- Constructor Title
Now we are faced with one more problem. The constructor of Foo
doesn't get initialized so we end up with an undefined this.baz
To resolve that we need to call the parent. In Java you would do that with super(vars)
, in PHP $parent->__construct($vars)
.
In Javascript we have to modify the Title
class constructor to call the constructor of the parent object.
So the Title
class constructor would become
function Title(what) {
Foo.call(this,what);
this.message = what;
}
By using the Function
object property Foo
inherited we can initialize the Foo
object in the Titl
e object.
And now you have a properly inherited object.
So instead of using a keyword like extend
like other OOP languages it uses prototype
and constructor
.
Constructor property : __proto__.constructor vs prototype.constructor
a.__proto__
is the Function
prototype (namely, Function.prototype
). It is the object from which all functions inherit function-specific methods like call
, apply
, bind
, etc. It is true that a.__proto__.bind == a.bind
.
a.__proto__.constructor
is the Function
constructor, i.e., the function Function
. The Function
prototype has a reference to its associated constructor via the constructor
property, as is always the default relationship between prototype object and constructor. (More on this "default relationship" in the next two paragraphs.)
Quite different is a.prototype
-- in JavaScript, any function can be a constructor, i.e., it may be called with new
. Whenever a function is called with new
, it creates a new object whose __proto__
is the function's prototype
and points to the newly-created object via this
. So inside a call to new a()
it is true that this.__proto__
equals a.prototype
. This prototype object is automatically created and stored in a.prototype
at the moment the function a
is defined.
a.prototype.constructor
is equal to a
, because the JavaScript internal routine that creates prototype
objects for newly-defined functions (as specified in the previous paragraph) always gives that new prototype a constructor
property that refers to the newly-defined function. To get really into the weeds, the relevant ECMAScript routine is 19.2.1.1.1, CreateDynamicFunction, which notes, "A prototype
property is automatically created for every function created using CreateDynamicFunction, to provide for the possibility that the function will be used as a constructor."
a
does not have its own constructor
property, but it automatically inherits a.__proto__.constructor
accessible as a.constructor
, just as it inherits any other properties on its prototype parent (just like a.bind
is really a.__proto__.bind
).
Finally, a.__proto__.constructor !== Object.prototype.constructor
because Object.prototype
is not a function object's prototypal parent, but instead Function.prototype
is. It is instead true that a.__proto__.constructor === Function.prototype.constructor
(and, more succinctly, a.__proto__ == Function.prototype
and a.__proto__.constructor == Function
).
__proto__ VS. prototype in JavaScript
__proto__
is the actual object that is used in the lookup chain to resolve methods, etc. prototype
is the object that is used to build __proto__
when you create an object with new
:
( new Foo ).__proto__ === Foo.prototype
( new Foo ).prototype === undefined
[[Prototype]] vs prototype: ..what is the difference? (MyCons.__proto__ === MyCons.prototype) equals FALSE
Think of it like this. MyConstructor
is a function object, so it was created by Function
; therefore its [[Prototype]]
(or __proto__
) is identical to Function.prototype
.
In the same way, var myObj = new MyConstructor()
creates an object myObj
with a [[Prototype]]
identical to MyConstructor.prototype
.
To put it another way, functions have a prototype
property, and when you invoke functions with new
, they will construct an object having a [[Prototype]]
identical to the constructor function's prototype
property... however a function's prototype
property is not the same thing as its [[Prototype]]
(or __proto__
) property, because a function follows the same rules as other objects and gets its internal [[Prototype]]
property from the function that constructed it (which is always Function
, incidentally).
To explain further, [[Prototype]]
and prototype
have entirely different purposes. [[Prototype]]
is used when resolving an object's properties. If an object doesn't have a property, its [[Prototype]]
is checked, and then that object's [[Prototype]]
, and so on, until either a property is found or you hit the end of the prototype chain.
In contrast, prototype
is the mechanism by which you assign [[Prototype]]
properties to objects, since you can't access them directly other than with the non-standard __proto__
property.
Since functions are objects, they have both a [[Prototype]]
internal property, used to resolve properties as with normal objects, and a prototype
property, which is assigned as the [[Prototype]]
of new objects constructed by the function.
Related Topics
How to Update State.Item[1] in State Using Setstate
Check If a Variable Is a String in JavaScript
Why Is My Infinite Loop Blocking When It Is in an Async Function
JavaScript Get Xpath of a Node
How to Use Multiple Refs for an Array of Elements with Hooks
Fetch Request to Local File Not Working
How to Determine Which Submit Button Was Pressed, Form Onsubmit Event, Without Jquery
Load HTML File Contents to Div [Without the Use of Iframes]
Jquery Click Anywhere in the Page Except on 1 Div
Is It Safe to Store a Jwt in Localstorage with Reactjs
JavaScript Checking for Null VS. Undefined and Difference Between == and ===
Alternation Operator Inside Square Brackets Does Not Work
Determine Original Size of Image Cross Browser
How Might I Find the Largest Number Contained in a JavaScript Array
Access Outside Variable in Loop from JavaScript Closure
How to Get Image from Canvas Element and Use It in Img Src Tag