https://javascript.info/constructor-new
The purpose of constructors is to implement reusable object creation code
Constructor functions technically are regular functions. There are two conventions though:
They are named with capital letter first.
They should be executed only with “new” operator.
Every function is an object, and when an object is created with “new”, it runs through the constructor.
1) The constructor then uses ‘this’ and assigns an empty object to it.
2) It will then add properties you specify onto “this”.
3) Finally, it returns this.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function User(name) { // this = {}; (implicitly) // add properties to this this.name = name; this.isAdmin = false; // return this; (implicitly) } let user = new User('Ricky'); console.log(user.name); // Ricky console.log(user.isAdmin); // false |
Constructors in Javascript is used to construct objects and can be called many times by any references.
However, constructors can also be created and called just once, and not be saved for later use.
1 2 3 4 5 6 7 8 9 10 11 |
let john = new function() { this.name = 'John'; this.isAdmin = false; // ...other code for user creation // maybe complex logic and statements // local variables etc }; console.log(john.name); // John console.log(john.isAdmin); // false |
DUAL SYNTAX: new.target
ref – http://chineseruleof8.com/code/index.php/2016/02/29/this-in-function/
Inside a function, we can check whether it was called with new or without it, using a special new.target property.
This can be used to allow both new and regular syntax to work the same. The reason why we care about “new” is because when we “new” a function, it creates an object out of it with its own “this”.
However, if we do not use “new”, the value of this becomes the global object.
In a web browser the global object is the browser window.
For example:
1 2 3 4 5 6 7 8 |
var Person = function(name) { this.name = name || 'johndoe'; // 'this' refers to the window object }; var cody = Person('Cody Lindley'); //console.log(cody.name); // UNDEFINED! console.log(window.name); //logs Cody Lindley, |
The reason why window.name logs Cody Lindley is because the ‘this’ inside the function references the window global object. Hence when we attach the attribute name to this, it attaches name to the window object. the ‘this’ has nothing to do with the object Person.
Now, when we use new Object, we create an object on the heap, and “this” in our function refers to that object. IT IS NOT connected to the (global or window) object.
Hence, when we log cody.name, it works because cody is that object in the heap. The this in the function, refers to cody.
In order to make sure the “new” is always applied so that we get some consistency, we can check for new.target to see if “new” was used to create the object. If not, then we need to force it by returning an object using new.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
function Node() { // this = {} // With new we all know that the new object is being created, that’s a good thing. if (!new.target) { console.log('You didnt use new. Giving you a new Node Object'); return new Node(); } // add properties to this this.data = 'NA'; this.next = null; // return this } let head = Node(); console.log(head.data); // NA console.log(head.next); // null |
Return from Constructors
Usually, constructors do not have a return statement. Their task is to write all necessary stuff into this, and it automatically becomes the result.
But if there is a return statement, then the rule is simple:
If return is called with object, then it is returned instead of this.
If return is called with a primitive, it’s ignored.
In other words, return with an object returns that object, in all other cases this is returned.
1 2 3 4 5 6 |
function BigUser() { this.name = 'john'; return {species: 'species', name: 'Godzilla'}; // returns is called with object } console.log(new BigUser().name); // Godzilla |
1 2 3 4 5 |
function SmallUser() { this.name = 'John'; return; // returns this } console.log(new SmallUser().name); // John |
Methods in Constructor
Having a method in a constructor means you add the method definition as a property to “this”. Once that happens,
after you construct an object, you are free to call that method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function ListNode(newData, newNext) { // this = {} // assign properties to self this.data = newData; this.next = newNext; this.display = function() { console.log('display data and next here'); }; // return this } let ListHead = new ListNode('hadoken', null); ListHead.display(); // display data and next here |
Is it possible to create functions A and B such as new A()==new B()?
1 2 3 4 5 6 7 |
function A() { ... } function B() { ... } let a = new A; let b = new B; alert( a == b ); // true |
Yes, it’s possible.
If a function returns an object, then new returns it instead of this.
So thay can, for instance, return the same externally defined object obj:
1 2 3 4 5 6 |
let obj = {}; function A() { return obj; } function B() { return obj; } alert( new A() == new B() ); // true |