In this course, I say:
The value of “this” inside of the constructor function is a new instance of that object type, where the “type” is defined by the constructor function, itself.
The question from the reader centered around type definitions and functions:
How does a constructor function define a type? Isn’t it just a function? What qualifies a function as a constructor function – other than the ‘new’ invocation pattern?
But that doesn’t mean every function out there is designed to work this way.
Constructing An Object From A Function
The .prototype attribute of the function is used as the prototype of the object instance, when you call the function with the “new” keyword.
The object is also said to be an instance of that function’s name… the “type” that was defined with the function.
The “s” object in these examples is clearly an instance of “something” with a prototype defined by that function.
But, how does that happen?
The Magic Of “new”
- Create a new object instance
- Assign its prototype to the function’s .prototype
- Apply the function with the object instance set as “this”
Granted, this is a greatly over-simplified representation of what happens, but it is the core of the process.
Because every function you define has a .prototype, and because of the way the “new” keyword behaves, it is possible to use just about any function as a constructor function to create new instances of that “type”.
But just because you can, doesn’t mean you should.
Not All Functions Are Created Equal
Most functions are just functions that do some work and maybe return some value.
You could use the “new” keyword in front of any random function, if you wanted to, but the results would not be predictable if it was not intended to be a constructor function.
For example, look at the following code and ask yourself what it would return as a plain function call vs a construction function call.
If you call this as a plain function, it will return the string as you would expect.
But what happens if you call it as a constructor?
In this case, the function no longer works as expected – the string that you wanted will not be returned.
Yet, in another example, the return value of the normal function will still return as expected:
In this case, both the standard function call and the constructor function call return the same value.
When you have a constructor function, there is an implicit return value – the new object instance. You are allowed to override this return value with your own object instance, though – as shown in the second example.
Don’t worry, though. It gets worse! And it does get better – especially moving forward with ES6 and beyond.
Object Methods As Constructors
So, what happens when you have an object with a method, like this one below, and you apply the “new” keyword to it?
The result is not a pretty site:
The use of this function as a constructor has clearly broken things.
The value of “this”, when the function is used as a constructor, is not the value of “this” that the function expected. It was designed to use the object itself as “this”, but that expectation was not met. The code tried to run anyways, and very bad things happened as a result.
But this isn’t always the case. There are times when you will have an object with a method, and it is meant to be used as a constructor function. For example:
In this case, “Company” is acting as a namespace, not a standard object. On the Company namespace, a “Department” type has been defined. This Department method is intended to be used as a constructor function.
So, what’s the difference between these two examples? How would someone know that a method is or is not supposed to be a constructor function?
Idiomatic Constructor Functions
In general, there is a common practice for naming functions with a capitalized name, to identify them as a constructor function. They also tend to be named as a noun.
being a capitalized function name, and being a noun, there’s a high likelihood that this is supposed to be a constructor function. Whereas, this function:
is not likely to be a constructor function.
The naming convention follows a standard for a function that just returns a value. It’s not capitalized, and it has the word “get” in it – a word that typically means the function will return some value.
ES6 Classes And Type Definitions
In this example, a simple “Bar” class is defined and a “doStuff” method is added. An object instance is created and the doStuff method is executed as expected.
Yes, there are some real differences in class syntax vs constructor function syntax, but once a class is defined, it is actually a constructor function (as shown by Node v4+):
As you can see in this output, the class Bar does produce a constructor function. However, it is not a “normal” function in that it cannot be called without “new”
This is one of many differences with ES6 Classes.
Functions And Type Definitions
The ability to use nearly any function as a constructor by using the “new” keyword means it is possible to get yourself into some sticky situations if you’re not careful. Just because you can use any function as a constructor, doesn’t mean you should. Idioms and good document should exist to help us identify which functions should be used this way.
Want To Know More About Types And Prototypes?