Reputation: 139
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:
{
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
Reputation: 23798
When you call a constructor function with the new
keyword, following things happen:
this
.this
, adds new properties to it.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.
The simple Animal constructor is declared. It will add live=true
to every animal.
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
.
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.
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.
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)
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
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