links: JS MOC
Definitions
Factory Function
A factory function is any function which is not a class or constructor that returns a (presumably new) object.
In JS any function can return an object. When it does so without the
newkeyword, it’s a factory function
Constructor Function
Constructor functions are like regular functions, but we use them with the new keyword. There are two types of constructor:
- built-in constructors such as
ArrayandObjectwhich are available automatically in the execution environment at runtime. - custom constructors, which defines properties and methods for your own type of object.
A constructor is useful when you want to create multiple similar objects with the same properties and methods. It’s a convention to capitalize the name of constructor functions to distinguish them from regular functions
function Book(name, year) {
this.name = name
this.year = year
}
const ydkjs = new User('You don\'t know js', 2018)When a function is executed with new, it does the following steps:
- A new empty object is created and assigned to
this - The function body executes. Usually it modifies
this, adds new properties to it. - The value of
thisis returned.
Read more about new keyword in JS
In other words, new Book(..) does something like:
function Book(name, year) {
// this = {} (implicitly)
// add properties to this
this.name = name
this.year = year
// return this (implicitly)
}So let book = new Book('ydkjs', 2018) gives the same result as:
let book = {
name: 'ydkjs',
year: 2018
}Now if we want to create other books, we can call new Book('design patterns', 1998). Much shorter than using literals every time, and also easy to read.
The main purpose of constructor function is to implement reusable object creation code
Note: Technically any function can be a constructor function. That is; any function can be run with new, and it will execute the algorithm above (see new keyword explanation in constructor function)
Determining the type of an instance
To find out whether an object is an instance of another one, we use instanceof operator
book instanceof Book // true
book instanceof Book // falseNote that if the right side of the instanceof operator isn’t a function, it will throw an error
book instanceof {}
// TypeError: invalid instanceof operand({})Another way to find type of an instance is to use constructor property. Consider the following
book.constructor === Book // trueNote that, using the constructor property to check the type of an instance is generally considered as bad practice because it can be overwritten
Advanced
Constructor Function
How to test a function is called with new?
Inside a function, we can check whether it is called with new or without it using a special new.target property
It is undefined (empty) for regular calls and equals the function if called with new:
function Book(name, year) {
console.log(new.target)
}
// without "new":
Book('ydkjs', 2018) // undefined
// with "new":
new Book('ydkjs', 2018) // function Book(name, year) { .. }That can be used inside the function to know whether it was called with new, “in constructor mode”, or without it, “in regular mode”.
We can also make new and regular calls to do the same like this:
function Book(name, year) {
if(!new.target) { // if you run me without new
return new Book(name, year) // ... I will add new for you
}
this.name = name
this.year = year
}
var ydkjs = Book("ydkjs", 2018) // redirects call to new Book
console.log(ydkjs.year) // 2018
Return from constructors
Usually constructors do not have a return statement. Their task is to write all the necessary stuff into this, and it automatically becomes the result.
But, if there is a return statement the rule is simple
- if
returnis called with an object, then the object is returned instead ofthis. - if
returnis called with a primitive, it’s ignored.
Example returning object:
function Book(name, year) {
this.name = name
this.year = year
return {
bookName: this.name
} // returns this object
}
console.log(new Book('ydkjs', 2018).name) // undefined
console.log(new Book('ydkjs', 2018).bookName) // ydkjsNow, only bookName will be available and name and year will not be available as return overridden this to another object
Example returning primitive:
function Book(name, year) {
this.name = name
this.year = year
return // return this
}
console.log(new Book('ydkjs', 2018).name) // ydkjsOmitting parentheses
We can omit parentheses after new, if it has no arguments:
let book = new Book / no parenthses
// same as
let book = new Book()
omitting parentheses is not considered as a “good style”, but the syntax is permitted by the specification.
tags: javascript , fundamentals , design-pattern