Charlie H Charlie H - 10 days ago 5
Javascript Question

Object.prototype and Function.prototype

In JS functions are said to be objects. Now when functions are tested against objects, they behave differently.

a = {};
console.log(a.prototype); //undefined

function myFunc() {};
console.log(myFunc.prototype); //Object
Object.getPrototypeOf(myFunc); //function(){}


And to make things worst, an example in this MDN article seem to change the constructor of a function prototype.


secondConstructor.prototype.constructor = secondConstructor;


Can someone please explain this behaviour?

Answer

What leads to a common confusion is that a function as an object has .__proto__ property and as a function has .prototype property. They have different meaning.

Most JavaScript objects have a prototype object, that can be accessed using Object.getPrototypeOf() method, or simply .__proto__ property. This is the object which is used to reuse code and is consulted when a property accessor can't find requested property on an object, then it's looked up on its prototype. This is how common methods like .apply are available on a function. This is how you access this object in your example:

Object.getPrototypeOf(myFunc); //function(){}

Only functions have .prototype property, which is used by new operator when a new object is created using the function. When a function is called with new operator and a new object is created, JS checks the .prototype property of the function. If it points to an object, JS sets this object as a prototype of a newly created object. That's why the .prototype of an object in your example is undefined:

a = {};
console.log(a.prototype); // undefined

Can someone please explain this behaviour?

secondConstructor.prototype.constructor = secondConstructor;

The constructor property of an object usually points at the function that was used to create the object. When a function is declared, this property is created automatically on the object that .prototype property of the function points to.

function c() {}
c.prototype.constructor === c; // true
var o = new c();
o.constructor === c; // true

However, this property can easily be changed:

c.prototype = {constructor: function notCAnymore() {}}
var o = new c();
o.constructor === c; // false

Now we don't have a reference to the correct function anymore. So after changing the prototype, we may need to restore the .constructor property:

c.prototype = {constructor: function notCAnymore() {}}
c.prototype.constructor = c; // restoring the correct constructor
var o = new c();
o.constructor === c; // true

And that is exactly what is done in the example. The prototype is changed:

secondConstructor.prototype = new firstConstructor;

If object is created now the pointer to a correct constructor is lost:

var o = new secondConstructor();
o.constructor === secondConstructor; // false

That's why they use this code to restore it:

secondConstructor.prototype.constructor = secondConstructor;
var o = new secondConstructor();
o.constructor === secondConstructor; // true
Comments