8

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.

Community
  • 1
  • 1
Flake
  • 1,386
  • 17
  • 31
  • 2
    http://es5.github.io/ knows nothing about `__proto__` at all. Which means it's not a part of the standard and you should never use it. – zerkms Jul 10 '15 at 12:20
  • No, the prototype of an object (the one with it inherits from) is **not** the `.prototype`. Have you read all answers to http://stackoverflow.com/questions/9959727/proto-vs-prototype-in-javascript? What did you not understand specifically (we're happy to improve them)? – Bergi Jul 10 '15 at 12:23
  • then what is .prototype used for?? – Flake Jul 10 '15 at 12:24
  • @Flake: [On constructor functions](http://stackoverflow.com/q/572897/1048572) – Bergi Jul 10 '15 at 12:29
  • 1
    so it means that '.prototype' is used as prototype of objects constructed by that function, but it has nothing to do with that function's own prototype – Flake Jul 10 '15 at 12:35

3 Answers3

19

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

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
  • 1
    two prototype for a function......dats confusing!!! – Flake Jul 10 '15 at 12:45
  • 1
    When you do myFunc.prototype = myObj; myObj is available to myFunc instances and not for myFunc it self. var x = new myFunc(); console.log(x.a); //returns 1 – prgmrDev May 16 '17 at 03:14
1

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
Josiah Keller
  • 3,635
  • 3
  • 23
  • 35
0

All JS objects have __proto__ system property. If you try to get the propery x value of an object a, first of all this property is searched among object a properties. If nothing found the property will be searched among a.__proto__ peroperties. And so on. That is why myFunc.a ruturns 1 in your example. When you set myFunc.prototype=myObj that means that myObj will be used in future when you create instances of myFunc:

var mf = new myFunc();

and that doesn't mean that myFunc must have a protpery itself, as I mentioned above.

Viktor Kireev
  • 1,200
  • 1
  • 8
  • 17