tonitone110
tonitone110

Reputation: 139

Can I simplify the instantiation of this constructor function?

Is it possible to break down the following code (especially the new keyword) into simpler code (so I can understand what's going on)?:

function F() {
  this.color = 'red';
  this.printNumber = function printNumber() {
    console.log(5);
  };
 }

 let o = new F();
 console.log(o);

Here is my attempt:

I thought I was onto a winner when I was told that let o = new F(); is the same as let o = F.call({}) but I can see on the console that the first additionally gives the empty object a constructor property set to the constructor function.

Is it very important that the new object has a constructor property set to the constructor function? I know that this constructor function would be considered a method and the this in there would refer to this object as a whole. Which leads me to think that the new works by:

  1. Instantly creating an object that has a constructor property set to the constructor function.
  2. Executing the constructor property (a method) so that the new object looks like:
{
color: "red",
printNumber: printNumber,
constructor: F
//as it is an instance of the inbuilt Object constructor function, it has all the properties/methods of an object
}

Upvotes: 1

Views: 88

Answers (2)

Charlie
Charlie

Reputation: 23798

When you call a constructor function with the new keyword, following things happen:

  1. A new empty object is created and assigned to this.
  2. The function body executes. Usually it modifies this, adds new properties to it.
  3. The value of this is returned.

The return object has in its prototype the constructor property which references the constructor function.

Now why is the constructor function in the prototype is important? It's all about object inheritance pattern in JS.

//Here is the Animal constructor
function Animal() {
   this.live  = true;
}

//Object methods are attached to the prototype. So, they have a single presence in the object hierarchy
Animal.prototype.move = function() {console.log('moving')}; 


//Here is the Cat constructor. This is how JS makes the Cat inherit from the animal.
function Cat() {
   Animal.call(this);   //The this keyword points to the Cat object being created
}

//Let's set its prototype
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;


//All is set. Let's create the child object    
let cat = new Cat();

Here are the sequence of events.

  1. The simple Animal constructor is declared. It will add live=true to every animal.

  2. It's prototype has the move method. So, any animal can move and this move function will not be instantiated - because it is in the prototype - not in this.

  3. Define the Cat constructor. It simple calls the Animal constructor without new. So, it will not create an Animal - but it will create all the animal properties in the resultant object.

  4. Set an Animal as the prototype of the Cat. Notice that it inherits the Animals prototype methods - namely move. This is why we say javascript has prototypical inheritance.

  5. Set the Cat constructor function to Cat. This is due to the fact that by point 4, the constructor function of the Cat too is Animal. We change it here. (yes - bizarre)

  6. Create a new Cat. This will call the Animal constructor without new, so, the cat has all the Animal properties. The cat can move - because it's prototype has the move method. And finally, it't constructor function is Cat - so, the new keyword will use it.


The new Ecmascript versions wrap this all in Class and does things automatically. But I believe that the fundamental understanding is important too.

Upvotes: 1

Scott Marcus
Scott Marcus

Reputation: 65796

Is it very important that the new object has a constructor property set to the constructor function?

If your intention is to create an object that you can instantiate and inherit from, then yes, you should use the new syntax. call() does just that, it invokes the function (runs its code) without formally instantiating an instance of the object. call() also allows you to define what this will bind to when the function runs, but call() and new are not the same.

When you instantiate with new an instance of the object is created and the constructor function executes. this is then bound to the new instance.

For more details on how new and prototypical inheritance works, see this other post of mine.

Also, fyi, you should add methods of your object (that operate the same no matter what particular instance you have) to the prototype of your object, not the object itself:

function F() {
  this.color = 'red';
}

// Methods are usually added just once to the object's
// prototype and then all instances inherit it, which
// has a lower memory footprint because the method is
// defined and attached just once instead of on each 
// instance.
F.prototype.printNumber = function printNumber() {
    console.log(5);
};

let o = new F();
console.log(o.color);
o.printNumber();

Upvotes: 1

Related Questions