peter.petrov
peter.petrov

Reputation: 39457

JavaScript - unexpected/strange constructor

var ninja = {
    name: 'Ninja',
    say: function () {
        return 'I am a ' + this.name;
    }
};

function F(){
}

F.prototype = ninja;

var ninja2 = new F();

ninja2.name;

Output >>> "Ninja"

ninja2.constructor === F

Output >>> false

ninja2.constructor

Output >>> function Object()

ninja2.__proto__ === ninja

Output >>> true

In this example, why is not F the constructor of ninja2
(as one would expect)?!

And I expect that because... the next example prints Hero.

function Hero(){ } 

var h1 = new Hero();

h1.constructor

Output >>> function Hero()

What is the conceptual difference?

I think it's related somehow to the fact that I set explicitly F.prototype = ninja; in the first example. But how is it related to that? I am confused about this. Isn't F the constructor of ninja2? After all new F() was used to create ninja2?

Upvotes: -1

Views: 53

Answers (2)

Oriol
Oriol

Reputation: 288120

The constructor property has no magic, it's just a property that is automatically added when you create a function object:

13.2 Creating Function Objects

  • Create a new native ECMAScript object and let F be that object.
  • ...
  • Let proto be the result of creating a new object as would be constructed by the expression new Object() where Object is the standard built-in constructor with that name.
  • Call the [[DefineOwnProperty]] internal method of proto with arguments "constructor", Property Descriptor {[[Value]]: F, { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true}, and false.
  • Call the [[DefineOwnProperty]] internal method of F with arguments "prototype", Property Descriptor {[[Value]]: proto, { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}, and false.
  • ...

Example:

function F(){}
F.prototype.constructor; // F

Therefore, when you overwrite F.prototype with another object, you lose the constructor property.

Then, when you use ninja2.constructor, you get Object because:

  1. ninja2 has no own constructor property.
  2. ninja2 inherits from ninja, which has no own constructor property.
  3. ninja inherits from Object.prototype, which has an own constructor property set to Object.

To fix this problem, you can

  • Restore constructor in F.prototype:

    function F(){}
    F.prototype = ninja;
    F.prototype.constructor = F;
    
  • Include constructor in ninja:

    var ninja = {
        constructor: F, /* ... */
    };
    
  • Add the desired properties to F.prototype instead of replacing it with another object:

    Object.assign(F.prototype, ninja); /* Requires ECMAScript 6 */
    

Upvotes: 2

intheweeds
intheweeds

Reputation: 79

You declare "F" as follows:

function F(){}

This will create a function object "F" with a prototype like this:

F.prototype = { constructor: F };

The "ninja" object you create has the Object() constructor by default. When you replace F.prototype with the "ninja" object, the following line of code now uses the Object() constructor from "ninja" because you overwrote F's prototype:

var ninja2 = new F();

Upvotes: 1

Related Questions