Memory Usage for JS Object Creations

I recently watched a YouTube video about creating JavaScript objects. It went over four different patterns: constructor, factory, prototype, and dynamic prototype. The author recommended one of them as his preferred way to create objects in JavaScript.

I wondered, “How would these different patterns look in terms of memory usage?” So I set to find out.

If you’re interested in watching the video, you can find the link at the end of this post. If not, here’s a quick takeaway:

Factory Pattern

const person = function(name, age, gender) {
let temp = {};
temp.name = name;
temp.age = age;
temp.gender = gender;
temp.speaks = function() {
console.log(`I'm ${this.name}, ${this.age}, ${this.gender}.`);
}
return temp;
}
let batman = person('Bruce Wayne', 30, 'Male');

Factory Pattern (my variant)

Because I was curious to see what happens if I don’t use a temp variable.

const person = function(name, age, gender) {
return {
name,
age,
gender,
speaks: function() {
console.log(`I'm ${this.name}, ${this.age}, ${this.gender}.`);
}
};
}
let batman = person('Bruce Wayne', 30, 'Male');

Constructor Pattern

const person = function(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
this.speaks = () => {
console.log(`I’m ${this.name}, ${this.age}, ${this.gender}.`);
};
}
let batman = new person('Bruce Wayne', 30, 'Male');

Prototype Pattern

const person = function() {};
person.prototype.name = ‘Unknown’;
person.prototype.age = 0;
person.prototype.gender = ‘Unknown’;
person.prototype.speaks = function() {
console.log(`I’m ${this.name}, ${this.age}, ${this.gender}.`);
};
let batman = new person();
batman.name = 'Bruce Wayne';
batman.age = 30;
batman.gender = male;

Dynamic Prototype Pattern

const person = function(name, age, gender) {
this.name = name || 'Unknown';
this.age = age || 0;
this.gender = gender || 'Unknown';

if (!this.speaks) {
person.prototype.speaks = () => {
console.log(`I'm ${this.name}, ${this.age}, ${this.gender}.`);
};
}
}
let batman = new person('Bruce Wayne', 30, 'Male');

The Takeaway

When we have multiple instances of person (e.g. batman and superman) using the constructor and the factory patterns, each of them will carry their own copy of name, age, gender, and speaks(). This means that each person require their own space in your computer’s memory.

The prototype pattern allows multiple instances to share default name, age, gender, and speaks(), while at the same time allows each instance (i.e. batman and superman) to override the defaults with their own value. This approach would take less space in the memory.

A minor drawback of the prototype pattern is that we lose the ability to initialize a person object in one line.

This brought us to the dynamic prototype pattern which essentially is the combination of the constructor and the prototype pattern. As you saw from the code, while each instance would have its own copy of the properties (name, age, and gender), it would share the method (speaks()) with the other instances because the method is defined in the prototype space. Also, we could then initialize a person in one line.


My Test Steps

I opened up the Chrome dev tools in a blank tab and proceeded to the Memory tab. Among the profiles, I chose the Record Allocation Type because it “shows memory allocations from your JavaScript functions.”

For the code, I created 1 million simple person objects, hoping to see significant difference, and stuff them in an array.

The next steps were to paste my code to the console, start recording, execute the code, and stop recording. After the recording stopped, I got some statistics that I could use for comparison.

The Results

Memory usage comparison for creating 1 million person objects

Personally, the unexpected thing comes from my variant of the factory pattern, where I return an object literal directly instead of creating a temp object and returning that. In my mind, that would be more efficient, but it’s obvious that I don’t understand fully how things work in the background.

I’m also unsure at this point why the constructor approach used way more memory.

The prototype and the dynamic prototype unsurprisingly used the least memory. Even though the latter used a bit more memory, it allowed us to initialize person in one line.

Conclusions

I’ve been switching back-and-forth with how I create objects, but I think the video settled it for me. In reality, it probably won’t matter unless I need tons and tons of person instances. However, it’s nice to know which approach I could use should such need arise.


Watch the video here.

What do you think? How do you create objects in JavaScript? Do my test steps lead to a safe conclusion? Do you have any insights into the nooks-and-crannies of object creation that are not covered by this article or the linked video?