Cleaning up our JavaScript code is easy with default parameters and property shorthands.
In this article, we’ll look at the best practices for object creation in our JavaScript code.
We’ll investigate the use of object literals, factory functions, Object.create
and constructors/classes.
Object Literals
We can create objects with object literal notation. It requires no class, constructor, or prototype to create.
We just put everything inside curly braces as follows:
const obj = {
a: 1,
b: 2
};
This is good for objects that are created only once.
If we need to create multiple objects that have the same structure, then we’ve to find another way.
Factory Functions
A factory function is a function that returns a new object.
For instance, we can write:
const create = () => ({
a: 1,
b(){}
});
const obj = create();
We call the create
object to return and assign the object:
{
a: 1,
b(){}
}
to obj
.
Factory functions cause memory bloat since each object has its own unique copy of the b
method.
Prototype Chains
We can create objects that inherit the properties of another object by using the Object.create
method.
This kind of inheritance is called the prototype chain.
For instance, we can use the method as follows:
const create = () => {
const parent = {
a: 1,
b() {}
}
return Object.create(parent);
};
const obj = create();
Now each object created with create
inherit the properties of the parent
object.
The object created always has the __proto__
property with the properties of parent
.
ES5 Constructor Functions
Constructor functions are functions that act as templates for objects.
Each object created as fields and methods from the constructor function.
All instances of it reference those fields and methods.
For instance, we can define one as follows:
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
return `hi ${this.name}`;
}
Then we can use the new
keyword to make an instance of the Person
constructor by writing:
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
return `hi ${this.name}`;
}
const joe = new Person('joe');
const greeting = joe.greet();
The greet
method is an instance method of the Person
constructor, so we can call it on the object we created from the new
keyword.
If we attach a method to the prototype
property of the constructor, then it becomes method of the constructor.
We don’t want to use this anymore because it’s long, ugly, and error-prone.
ES6 Classes
The better way is to use ES6 classes, which is syntactic sugar on top of ES5 constructor functions.
They’re the same thing with a better syntax.
Therefore, we can rewrite the example above by writing:
class Person {
constructor(name) {
this.name = name;
}
greet() {
return `hi ${this.name}`;
}
}
const joe = new Person('joe');
const greeting = joe.greet();
console.log(greeting);
In the code above, the following:
class Person {
constructor(name) {
this.name = name;
}
greet() {
return `hi ${this.name}`;
}
}
is the same as:
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
return `hi ${this.name}`;
}
The rest of the code is the same between both examples.
Performance
The class syntax is roughly 3 times faster than a factory function returning an object literal.
That’s more reason to use the ES6 class syntax. It’s faster for both developers and browsers.
Private Data
We can encapsulate private data with closures and weak maps.
We just have to add private variables to lets of classes and functions with let
and const
. Then they won’t be available outside the function.
Weak maps can only be retrieved if the reference to the key still exists. Once it’s destroyed, then the value of the given key is gone.
They all let us mix different properties into one constructor or object into one entity.
Conclusion
Object literals and factory functions provide easy ways to create one-off objects.
If we want to create multiple objects with the same structure, then we’ve to use classes or the Object.create
method.
The class syntax creates objects faster than factory function, so that might be a plus for using classes.