DEV Community

Nico Zerpa (he/him)
Nico Zerpa (he/him)

Posted on • Edited on • Originally published at nicozerpa.com

I Don't Use JavaScript Classes At All. Am I Missing Out on Something?

If you spend time reading about JavaScript and keeping up with the latest stuff online, you'll notice that many discussions revolve around classes. But if you don't use them, you might feel like you're "stuck in the old ways". What are you missing out on if you don't use classes?

Thankfully, it's definitely possible to write correct, scalable code without classes. There are very few instances in which classes are necessary.

Also, classes in JavaScript have a subtle difference from other languages like Java. This small difference can be confusing and introduce bugs that are hard to find. And dealing with classes mean that you'll have to deal with the dreaded this keyword.

Being a multi-paradigm language, JavaScript also works well with features from functional programming. You can:

Compose functions, calling a function, and pass the returned value to another function:

functionA(functionB(value))
Enter fullscreen mode Exit fullscreen mode

Partially apply functions, call a function with just some of the arguments. It returns a function that you can call with the remaining arguments:

function flowerColour(flowerType, colour) {
  return `${flowerType} are ${colour}`
}

/* Call `flowerColour` partially, setting the 
  `flowerType` argument to "Roses" */
const rosesAre = flowerColour.bind(null, "Roses")

console.log(rosesAre("red")) // Returns "Roses are red"
Enter fullscreen mode Exit fullscreen mode

Use and create higher-order functions, these are functions that take a function as an argument or returns a function:


/* Map is a higher-order function, because
   it takes a function as an argument */

// Returns [10, 16, 37, 9]
[20, 32, 74, 18].map(number => number / 2)


/* Another higher order function, in this
   case, it returns a function */
function createLuckyNumber(name) {
  const luckyNumber = parseInt(10000 * Math.random())
  return function() {
    return `${name}'s lucky number is ${luckyNumber}`
  }
}

const emmasLuckyNumber =  createLuckyNumber("Emma")
const joesLuckyNumber = createLuckyNumber("Joe")

// Returns "Emma's lucky number is 7280"
console.log(emmasLuckyNumber())

// Returns "Joe's lucky number is 2971"
console.log(joesLuckyNumber())
Enter fullscreen mode Exit fullscreen mode

The last example created a closure. You create a closure when you create a function inside a function. This inner function has access to the variables from the parent function. The closure is the combination between the inner function and the variables from the parent.

For example, when you call createLuckyNumber, it reads the name, creates the lucky number, and returns an inner function. Even after createLuckyNumber was called, the inner function still can read the person's name and the number. Closures are an alternative to private fields in classes.

With these functional tools, you can also extend with libraries like Lodash, you are ready to write readable, performant and scalable code without classes.

What Make Classes Tick

There's a situation in which I use classes and I think it's the best way to use them. Classes are good when you want to isolate a complex task from the rest of the application.

This kind of class is like a "black box". That's because the rest of the codebase doesn't know (and doesn't care) about how the object works internally.

Most of its properties are private. Some of them might be public, and these properties can't be changed from outside the object unless it's strictly necessary. That's because that could mess with the object's inner workings.

(Note that JS still doesn't support private members, in this case, I just don't access them from outside the class.)

You should avoid using setter methods unless strictly necessary because it's the same as changing the object's properties from the outside.

When you need some functionality from the object, you can call one of the public methods, which performs an operation and returns the desired value.

The public methods consist of actions and operations that the object can do. For example, in a Car class, having an accelerate method is better than, say, setSpeed.

But in the end, this is a way to manage internal state, because the private properties of an object are its state. For that reason, I don't use classes in projects with a state management library. So even in this case, classes aren't really necessary.


p.s. Did you like what you've read? Every week I send an email with free tips and insights to become a better JavaScript dev. If you're interested, click here to subscribe.

Latest comments (25)

Collapse
 
levimichael profile image
Levi Whalen

I think for someone like me who comes from the front end to the back end, the idea of classes felt strange to me. Why am I defining something that is getting passed to me from somewhere else? I think it makes more sense when you think about using JavaScript end to end. Defining a class in the api to be used from back to front really helps you understand why you’d use it. Throw in typescript and things get even more fun.

Collapse
 
manonbox__ profile image
Ollie

I use classes when it makes sense from a readability point of view. Whenever I find myself writing a bunch of functions that are related, take in similar or same inputs (i.e. a bunch of related functions all depending on similar variables) then I think you can move this to a class.

This allows you to group your functions together, and reduce or eliminate the arguments they take, as they can use properties set by the constructor.

You can achieve exactly the same by not using a class. You can write lots of functions in a module, or simulate a class behaviour with a closure. You can always get the same result by not writing classes, but I would challenge if they are as readable as a simple class.

Collapse
 
gwutama profile image
Galuh Utama

Honestly though, classes make UML diagrams straightforward, which are important for enterprise software documentation.

However, Iā€˜m also okay with JS modules which consist only of functions. Describing them im UML diagrams are easy as well.

Collapse
 
taufik_nurrohman profile image
Taufik Nurrohman

The thing that’s a bit off with the class syntax is that we can actually create more methods on the class itself without extending it to another class:

class Foo {
    bar() {}
    baz() {}
}

Foo.prototype.qux = function() {};
Enter fullscreen mode Exit fullscreen mode
Collapse
 
__manucodes profile image
manu

Same here I don't use classes.
I use functions instead šŸ¤”

Collapse
 
breno profile image
Breno Farias Fonseca

You may never need it, but I can't see any other solution to better understand business rules than to abstract everything into classes and use good object-oriented practices. Another important point is that functional programming is not simply creating partial applications and using them later, there are several practices that, in my view, are more complex than the design patterns related to OOP.

Collapse
 
urielsouza29 profile image
Uriel dos Santos Souza

Familiarity Bias

Collapse
 
theoboldalex profile image
Alex Theobold

One of my favourite use cases for a JS class is for building a custom service response wrapper that ensures consistency in the way my APIs return JSON. For example, I might want to send along a success prop and a message with my data whereby I can pass custom messages back to the client from my API.

A very simple example...

class ServiceResponse {
  constructor(data = "", success = true, message = "") {
    this.data = data;
    this.success = success;
    this.message = message;
  }
}

module.exports = ServiceResponse;
Enter fullscreen mode Exit fullscreen mode

This allows me to return a default success value of true and an empty message on each call along with the data unless something goes wrong, in which case, I can return early and set the success and message values appropriately.

Collapse
 
emil profile image
Emil

bigger applications need more encapsulation. If you still are able to do that with functions and modules go for it. But depending on your preferences classes can help you to structure your code which is hard to do only with functions. Sure JS is no OO language but classes and SOLID principles work well with it

Collapse
 
stojakovic99 profile image
Nikola Stojaković

Classes are just syntactic sugar on top of prototypes.

Collapse
 
darkle profile image
Coop

One particular place I find classes useful is when you want to create your own errors. In that case you can just extend the regular built in Error class and add properties to it. Then you can check for it with MyError instanceof Error.