_Proto_ Vs. Prototype in JavaScript

__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

Difference between __proto__ and [[ Prototype ]] in javascript

Each object's prototype is saved in the internal slot named as [[prototype]] and __proto__is just a getter/setter, defined in the Object.prototype object, to get the value of the [[prototype]] internal slot of any object.

Example:

const arr = [];

Each instance of an array gets Array.prototype as its prototype. So, in the above declaration of arr, [[prototype]] internal slot contains a reference to Array.prototype and in the following expression:

arr.__proto__ === Array.prototype  // true

arr.__proto__ gets the Array.prototype object from the internal [[prototype]] slot.

As mentioned above, __proto__ is just a getter/setter that gets the value of [[prototype]] internal slot and is only there for compatibility reasons. It shouldn't be used in modern javascript code; following two methods should be used to set/get the prototype of any object:

  • Object.setPrototypeOf()

  • Object.getPrototypeOf()


There are other internal slots, apart from [[prototype]], mentioned in the Ecmascript specification and these internal slots are not accessible by the javascript code we write.

If you need to know more about internal slots, read:

What is an "internal slot" of an object in JavaScript?

__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.

[[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.

__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

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
Sample Image

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);

Function object __proto__ and prototype property

You already know that Object.getPrototypeOf(Animal) (or Animal.__proto__) is the Function.prototype object. So let's drop that Animal thing and just repeat your equations with Function.prototype:

Function.prototype.constructor.__proto__ == Function.prototype.constructor.prototype // true
Function.prototype.constructor.__proto__ == Function.prototype // true

Now, the .constructor property of Function.prototype (like for all well-defined prototype objects) points to its respective constructor, the Function constructor function. So we've got

Function.__proto__ == Function.prototype // true
Function.__proto__ == Function.prototype // true

Now, given that Function is a function, it only makes sense that it inherits from Function.prototype like all other functions do.

This is what your testing confirms, as you basically did

Function.__proto__.test = 28;

Function.__proto__.test // 28
Function.prototype.test // 28

And yes, Function.test and Animal.test would yield 28 as well now.

Object.getPrototypeOf() vs .prototype

TL;DR

function MyConstructor() {}

var obj = new MyConstructor()

Object.getPrototypeOf(obj) === obj.prototype // false
Object.getPrototypeOf(obj) === MyConstructor.prototype // true

MyConstructor.prototype // MyConstructor {}
obj.prototype // undefined

MyConstructor.prototype.constructor === MyConstructor // true
Object.getPrototypeOf(MyConstructor) === Function.prototype // true

The confusing part about prototypes in javascript is that there are 2 different things that sound very similar.

When you create a new object, if the function or object used to create the new object has a .prototype method, then the object referenced by .prototype will become the new object's prototype newObj.__proto__.

Sounds complicated... let's break it down further.

A. The .prototype property

Example - Using a function as a constructor

When you use the new keyword on a function (i.e. you use the function as a constructor) then the function's .prototype becomes the new obj.__proto__.

Lets first make a function and checkout this .prototype property

function MyConstructor(){
}

console.log(MyConstructor.prototype) // {}

Wait up... MyConstructor.prototype // {} - did something magically happen? Where did this empty object {} come from?

2 things here:

  1. Javascript automatically creates a .prototype object whenever you declare a function - automagically.

  2. This object is not empty. It actually has a property that points back to the function that created the object (the object's 'constructor'). Let's check it out:

console.log(MyConstructor.prototype.constructor); // [Function: MyConstructor]

MyConstructor.prototype.constructor === MyConstructor // true

So for functions, the .prototype property and it's associated object are created automatically.

Still confused? Lets add some methods in there to make it easier to see what's going on...

function MyConstructor(){
}

MyConstructor.prototype.func2 = function(){
};

console.log(MyConstructor); // [Function: MyConstructor]
console.log(MyConstructor.prototype); // MyConstructor { func2: [Function] }
MyConstructor.func2(); // TypeError: MyConstructor.func2 is not a function

Clearly we can see from the above code that MyConstructor and MyConstructor.prototype are 2 separate entities.

B. An object's prototype

An object's prototype (not .prototype - see A. above) is what javascript uses to lookup and resolve methods that aren't already in the object (more on this later).

Continuing on from above, when we create an object from a function or object that has a .prototype property, the newly created object will have it's object.__proto__ referencing this .prototype object.

An object's prototype can be accessed by

Object.getPrototypeOf(obj)

or the deprecated

obj.__proto__

Example - Using a function as a constructor

Lets make a new object using the function MyConstructor as a constructor.

function MyConstructor(){
}

var obj = new MyConstructor()

console.log(Object.getPrototypeOf(obj)); // {}

Here are the three relevant things:

  • MyConstructor (a function)
  • obj (an object that was created from MyConstructor)
  • obj.__proto__ --> MyConstructor.prototype

So obj.__proto__ is MyConstructor.prototype. Here is the proof:

MyConstructor.prototype === Object.getPrototypeOf(obj)  // true

Lets add a method to MyConstructor

function MyConstructor(){
this.func1 = function(){
console.log("this is func1");
};
}

var obj = new MyConstructor();

obj.func1(); // this is func1

From the above you can see that you can call methods that were declared in the constructor. In fact, if we have a look, our declared method func1 is actually part of obj due to the way javascript creates objects.

console.log(obj); // MyConstructor { func1: [Function] }

We can also add methods that obj can use by adding the methods to the prototype. e.g.

MyConstructor.prototype.func2 = function(){
console.log("this is func2");
};

obj.func2(); // this is func2

MyConstructor and MyConstructor.prototype methods will be available to all objects created using MyConstructor using this setup.


Useful References

Definitive Guide to Object-Oriented JavaScript

Understanding JavaScript: Inheritance and the prototype chain

A Plain English Guide to JavaScript Prototypes



Related Topics



Leave a reply



Submit