How to clone class instance in JavaScript

One very common scenario for wanting to clone a class instance is inside a function.

Why there’s a need to clone objects/arrays inside functions

Because non-primitive data structures are passed by reference in JavaScript, we will inadvertently mutate the original object or array passed into a function as an argument. Here’s a quick illustration of this behaviour:

In the above, userJohn was mutated inside the maskSensitiveInfo() function. Specifically, the line user[field] = 'hidden'; mutates userJohn directly instead of mutating a copy of it.

This behaviour is expected for non-primitive data types; that is, any variables that hold a data type other than the 6 primitives (boolean, number, string, symbol, null, and undefined).

I think it’s also the reason why many JavaScript code style guides I’ve come across so far recommend not mutating arguments within functions. Airbnb’s style guide is an example.

How to shallow copy an object

Instead, they recommend creating a copy of any object/array inside functions – basically as a preventive measure to eliminate the potential for unwanted (and hard to trace) side effects caused by mutating something outside of the function from within.

In the above snippet, the maskSensitiveInfo() function now creates a copy of the user object being passed in and uses it for intermediate steps that mutate it, before returning it. That’s why userJohnMasked is no longer the same object as userJohn (ie. userJohnMasked === userJohn evaluates to false).

Caveat for shallow copy: only one level deep

What we’ve just seen is shallow copying. It’s so-called “shallow” because Object.assign() is only going to copy over the first-level values and assign that to a new object. If, for example, userJohn has a key called “account” and its value is another object, that object is not copied but is once again only referenced.

This snippet illustrates the point:

The original object, userJohn, is accidentally mutated by the line userClone.account.number = 'hidden'. This is one of those horrible bugs that can be really hard to pinpoint.

To do a deep copy (vis-a-vis shallow copy), it’s best to use an external library like jQuery or Lodash:

More details on deep cloning can be found in this SO thread.

So that’s how you shallow/deep clone objects created from using the object literal syntax var x = {}; or var x = Object.create();, meaning they are literally constructed directly from the Object class in JavaScript.

What about objects that are instances of a custom implemented class? As we’ll see, because we will most likely have methods implemented on custom classes, the methods above will not suffice – the instance methods will not be copied over!

Cloning a class instance including its methods

I recently found out something that wasn’t obvious to me – apparently, methods defined within a class definition are automatically added to the prototype chain of the instance object.

So, to copy over the methods from one class instance to another, we will need to copy the prototype chain on top of copying the instance variables.

Here’s the magical series of built-in methods that can be used to create a copy of an instance of a custom-implemented class:

That’s quite horrid syntax on first and second glance, but on third glance…

Here’s how it works:

  1. Object.create() creates a new object and Object.getPrototypeOf() gets the prototype chain of the original instance and adds them to the newly created object
  2. Object.assign() does as we’ve seen earlier, which is to (shallow) copy the instance variables over to the newly created object

This comes in really handy for custom-implemented classes like Stack or Queue or LinkedList.

However, sometimes you will need to add a few extra lines to the copyInstance() method, depending on whether your class has any instance variables that need to be copied as well. In my case, I had to clone an array that is stored as an instance variable called this.stack within the Stack implementation:

Here’s the use case I recently had with a Stack (it uses ES6, so in case you’re unfamiliar, just treat all const and let as vars):

Summary

I didn’t intend for this post to get so long, but I wanted to be complete with my examples because I know it’s important contextual information for wrapping your head around the idea of cloning.

Here’s a summary to make it easier:

  • Non-primitive data types like Objects and Arrays are passed by reference into functions, unlike for primitives which are passed by value
  • Passed by reference implies that if a function mutates or reassigns an argument that is an object or array, the original variable outside of the function also gets mutated/reassigned – this can become a nasty, hard to uncover bug
  • For the above reasons, Airbnb, among other companies, eschew direct mutation or reassignment of arguments within functions
  • The solution is to create a clone before working with the cloned variable inside the function to prevent side effects
  • There are two types of cloning: shallow and deep
  • Shallow only clones one layer deep, which means if any key-value pair in an object contains another object, or if an object is stored as an item in an array, those continue to be references instead of cloned values
  • Deep cloning accounts for nested objects by effectively creating copies recursively until the deepest layer, ensuring there are no connected references to the original object
  • To clone an instance of a custom-implemented class, including its custom-implemented methods within the class, you need to copy over the prototype chain (because methods defined inside a class are added to the prototype chain) as well as the instance variables

I’m mainly writing this to ensure I have a note on this esoteric but essential part of JavaScript, but I certainly hope it was helpful to you in some way too!


Enjoyed reading this? I’ve been writing posts like these revolving around technology, society, and life on and off for more than a year now. This year I’m aiming for 5 posts per week, and I’d love to have you join me on that personal journey. You can read more at my blog or subscribe to get the most interesting posts delivered to your inbox – it’s free.

Conceptual overview of Jest Enzyme testing

jest and enzyme testing blog post banner nickang

I recently had the privilege of introducing frontend testing to our code base at work. With 5 engineers working on different parts of the product at any given time, it finally made sense to add automated tests. I can foresee this helping us cut down time spent on debugging and improving the overall quality of the product.

Because our frontend stack was React and Backbone, we needed a test library that can test React components. Some deliberation later, we decided to go with Jest (by Facebook and used internally at Facebook) and Enzyme (by Airbnb and also used internally at Airbnb).

Continue reading “Conceptual overview of Jest Enzyme testing”

Bubble sort explained

bubble sort explained banner
Photo by Sime Basioli on Unsplash

The goal of bubble sort is to sort an array in ascending or descending order according to a sortable property.

In our example below, we just use an array of integers to directly simulate the sortable property (a number), but in reality, you can imagine that that probably isn’t a frequent use case. What’s probably more common is sorting an array of objects by one of their properties, like IDs.

Continue reading “Bubble sort explained”

What is DRY (in programming)?

what is dry blog banner nickang showing weed growing on white wall
Photo by Ben Neale on Unsplash

Ever heard someone tell you that your code is not “DRY”? What’s the deal with that? Are they saying that your code can hold a lot of water…?

Sorry for the bad joke. DRY is an acronym, and it stands for Do not Repeat Yourself. As far as I can tell so far in my short career as a software engineer, this is one of the most revered principles in writing software.

In this post, we’ll explore why it’s important to keep your code DRY and in general, how you can go about doing it.

Continue reading “What is DRY (in programming)?”

Algorithm time complexity and the Big O notation

bite size programming algorithm time complexity and big o notation banner
Photo by Lysander Yuen on Unsplash

Big O notation has attained superstar status among the other concepts of math because of programmers like to use it in discussions about algorithms (and for good reason). It’s a quick way to talk about algorithm time complexity.

While it’s a math concept that applies to various fields, programmers are probably one of the most frequent users of Big O. We use it as a shorthand to discuss how quickly and/or with how much memory an algorithm takes to go from start to finish.

Perhaps the part about Big O being most used by programmers is just my carpal-tunnel-visioned mind speaking, but nevertheless! It’s an important concept and here’s a post dedicated to understanding the Big O notation.

Continue reading “Algorithm time complexity and the Big O notation”

Encoding for programmers

red book with 8 bit bytes carved on the cover
Photo by Hope House Press on Unsplash

I’ve been running into Unicode and ASCII and related encoding/decoding issues recently at work. We had an email that didn’t get sent out and all I got was an error message that said that some character could not be encoded in ASCII as “ordinal out of range”. That set me back for many hours and I only think I’ve managed to fix it (by wrapping u” around every string in the affected module in Python).

Continue reading “Encoding for programmers”

You don’t know everything

By you I mean I. I’m ready to admit, I don’t know everything.

It’s an admission that doesn’t cause me to blush but makes me feel stronger. By acknowledging how little I know, I’m motivated to find out more about a topic.

With a few months of work as a software engineer under my belt now, I have a good sense of my standing among other software engineers in the field. Form a technical standpoint, I’m far from good. I mean on a scale of 1 to 10, with 1 being practically useless, I think I’m at 5 – not completely useless but still having a lot to learn.

Now that’s an admission you won’t see very often, especially if that person is looking to climb the professional ladder…

But I think it’s important and necessary to be truthful to yourself once in a while.

On most days you can “hustle” and pretend that you got your shit together and can do these amazing things. That brings with it numerous benefits, like better team morale, higher likelihood of having the person on the opposite end of a business transaction partially fooled, and an overall sense of self satisfaction. It’s good and it’s necessary, since we’re all imposters in some ways until we are not.

But I deeply believe that in the occasional moments when we are truthful to ourselves, we make the most progress, personally and professionally.

So allow me to admit that I’m not that good a software engineer yet. To be specific, based on my recent experiences at work, I know I need to work these specific areas:

  • Embracing a different language and framework from what I’m used to (Python and Django)
  • Being able to tell in at least half of all decision-making occasions whether Approach A or B is going to be a better decision down the road
  • Bridging the gap between my typing and thinking speeds so I can create features and fix bugs quicker (I think much slower than I can type at 105 WPM)

Now I have a list. Great, another list!

I’m being half sarcastic there. Only half.

I believe in lists and know a few good people who do too. Lists make concrete the floaty “I think”s, which in turn makes it possible for me to break through them.

With this list what I’m going to do is to break it down further into sub-lists. For example, I’ll make a list of things that answers this question: what’s stopping me from embracing Python and Django?

  • The syntax looks different from JavaScript
  • Resentment towards the fact that if we used NodeJS instead of Django on the project, I’d be able to code entirely in JavaScript (this is funny because I once lamented how difficult it is to set up a NodeJS server)
  • Not knowing enough to write code without having to cross- and double-check everything in the documentation and existing code

And then from there I’m going to come up with questions, this time as specific as possible, that would help me overcome this sub-list:

  • Why do you need to import so many basic features in Python? (I have a hunch for this answer, but knowing the philosophy of Python’s creators might offer insights into how I should be thinking about the language)
  • Why are Django controllers called views? That really confuses the shit out of me and I know I’m definitely not alone
  • What mental hacks can I use to convert my mind to thinking in Django’s terms?
  • Why do I need to deal with Serializers in Django when I don’t have to in a similar framework like Ruby on Rails?
  • What does class Meta: do in a Django model?
  • How exactly do you set up a REST API in Django REST Framework?
  • What’s the easiest way to pretty-print things in Terminal when working in Python and Django?

Man, the list is long!

But that’s how you know you know nothing. Jon Snow.

Perhaps it might be helpful to other software engineers looking for answers to these questions, so I intend to share my findings in another post. Enter your email in the box in the right panel to get notified to come read it when it’s out.