Learn about functions that return functions
In JavaScript, functions can be used as templates for creating other objects. These functions are called constructor functions and have special properties that are different from regular functions.
Defining Constructor Functions
They can be called with the new
keyword to construct a new instance of an object from constructor functions.
Also, they’re different from regular functions in that their name should start with a capital letter.
A simple example of a constructor function would be the following:
function Person(name, age) {
this.name = name;
this.age = age;
}
It’s important to note that we used the function
keyword to define the constructor function. We need to use it because arrow functions can’t be used to define constructor functions.
this
is an object that has the data of the object instance created by the new
keyword.
With this function, we can create a new Person
object by writing:
let person = new Person('Joe', 10);
In the Person
function, this.name
and this.age
are properties of object instances that are created with the new
operator.
this.name
of the person
object would have the value 'Joe'
, and this.age
would have the value 10.
If we create another instance of the Person
object by writing …
let jane = new Person('Jane', 11);
… then the this.name
of the jane
object would have the value 'Jane'
, and this.age
would have the value 11.
Every instance of the Person
constructor will have its own property values.
Methods in Constructor Functions
To make object instances created with constructor functions do something, we can add methods to it.
We can define methods in constructor functions by writing:
function Person(name, age) {
this.name = name;
this.age = age;
this.greet = function(){
return `Hi ${this.name}`;
}
}
In the code above, the this.greet
property is a method of a Person
instance. So if we create a new Person
object with the constructor and call greet
as follows …
let person = new Person('Joe', 10);
console.log(person.greet());
… then we get 'Hi Joe'
from the console.log
output.
Notice we used the function
keyword to define the method. We have to use it to get the instance of the Person
constructor as the value of this
.
If we create another instance of the Person
object, as follows …
let jane = new Person('Jane', 11);
… when we call thegreet
method on jane
as follows …
console.log(jane.greet());
… then we get 'Hi Jane’
from the console.log
output.
Constructor-Mode Test
It’s easy to mistakenly call a constructor function without the new
keyword. We can check if we used the new
keyword to call the constructor function by using the new.target
property.
For example, given we have the Person
constructor …
function Person(name, age) {
this.name = name;
this.age = age;
}
… then we can log the new.target
property, as follows:
function Person(name, age) {
this.name = name;
this.age = age;
console.log(new.target);
}
Then, once we create a new Person
with the new
operator, as follows …
let person = new Person('Joe', 10);
… we get the code of the function logged, as follows:
ƒ Person(name, age) {
this.name = name;
this.age = age;
console.log(new.target);
}
If we call the Person
function without using the new
operator, as follows …
Person('Joe', 10);
… we get undefined
returned from the console.log
.
Therefore, if we want to check if the constructor has been called with the new
operator, we can check the new.target
property.
Return From Constructor Functions
Just like regular functions, we can have a return
statement in a constructor function.
However, unlike regular functions, there are some rules that control what gets returned in constructor functions.
If return
is called with an object, then the object is returned instead of this
. When we create a new object instance with the new
operator, then we get the object returned instead of the value of this
.
If return
is called with a primitive object, then it’s ignored.
In all other cases, this
is returned even without specifying anything.
We can return an object other than this
by writing the following code:
function Person(name, age) {
this.name = name;
this.age = age;
return {
name: 'Mary'
};
}
Then, when we create an instance of Person
with the new
keyword, as follows …
let person = new Person('Joe', 10);
console.log(person.name);
… we get 'Mary'
logged.
Omitting Parentheses
We can omit parentheses when we invoke the constructor function if we don’t have to pass in any argument. For example, if we write …
function Employee() {
this.name = "John";
}
let employee = new Employee;
console.log(employee.name);
… we get 'John'
from the console.log
output.
Checking if an Object Is an Instance of a Constructor Function
We can check if an object is an instance of a constructor function by using the instanceof
operator.
For example, given we have the Person
constructor and a person
object created from it, as follows …
function Person(name, age) {
this.name = name;
this.age = age;
this.greet = function(){
return `Hi ${this.name}`;
}
}
let person = new Person('Joe', 10);
… we can use the instanceof
operator as follows to check if person
is created from the Person
constructor:
console.log(person instanceof Person);
The console.log
above should show true
. It’ll be false
if an object isn’t created from the constructor given.
For example, if we have …
function Person(name, age) {
this.name = name;
this.age = age;
this.greet = function(){
return `Hi ${this.name}`;
}
}
function Foo(){
}
let person = new Person('Joe', 10);
console.log(person instanceof Foo);
… then console.log
shows false
since person
isn’t created from the Foo
constructor.
Constructor functions are templates for creating objects. We can use it to create different objects using the same constructor, which has the same instance methods and properties with different values for the nonmethod properties.
We can use the instanceof
operator to check if an object is created from a constructor.