JavaScript Classes: The Inclusive Guide
Simply-put, cat-based examples of Classes, Instances, and Methods.
While conducting junior coaching recently, I noticed some confusion around classes, and vocabulary related to them. Although it is known that ES6 introduced class syntax, similar to what can be found in other programming languages, it’s not much help to those who are new to programming.
If you find yourself a bit puzzled as well, I hope this article will help to clear things up.
What the Class?!
In object-oriented programming, a class is an extensible program-code-template for creating objects, providing initial values for state (member variables) and implementations of behavior (member functions or methods).
— Wikipedia
Long story short, class is a blueprint to build objects of similar shape. You could think of class definition as of a page from the dictionary:
Which, translated to JS, becomes:
That speak() thing is called a method of the Cat class.
Methodical Methods
You could think of methods as actions that can be performed on the object.
They can be called almost* whatever you want. Good practice is using verbs of imperative mood, written down in camelCase (as opposed to class name, which is UpperCamelCase).
*almost — constructor is a special method, more about it later on.
But hey, cat is something much more than just a meowing machine! — you might say. Fair point, let’s boost it up a bit:
You may have noticed that the constructor method accepts a parameter of name, which by default is set to ‘Anonymous’. Also, speak method now accepts a parameter, which gets destructured to introduce a variable (false by default) - this allows you to use named parameters in JS. Those are some of the cool, widely used ES6 features.
All cool, but after all, I like meowing. Can we please just make it meow? — you could ask. The answer would be…. not yet, because at this point we have no cats around. These are only definitions. No fur, no meowing — just pieces of paper pulled from a dictionary!
Instant Instance
We can agree that knowing what a cat is, differs from actually having a cat.
It’s the same with classes: after defining one there comes a time to instantiate it.
You could think of these instance as of an “incarnation” of class: it’s the actual object, built based on the blueprint that the class describes.
Constructive Constructor
In Fig. 3 you may have noticed a method called constructor. It is used to set the initial state (eg. instance property name, in this case) of a created object. It’s a special method that gets invoked automatically when creating a new instance of a class:
As luna is an instance of class Cat, it has all the useful methods we defined earlier. Also, it has a property name set to ‘Luna’ (which is what we passed to the constructor in Fig. 4)
It appears that our luna has a tail, fur, and two ears. So, she is definitely starting to look like a cat. And look, she meows:
And a proper cat, at that! As mentioned before, the class is a blueprint to create similar objects. So in an instant, we can have as many cats as we wish. They will all have the properties, and skills defined within their class (such as meowing):
But Luna was darker and not all cats look the same! — you’d argue, being right again. As mentioned earlier, classes are blueprints for similar objects, not necessarily identical ones. Some differences can be managed through constructor function parameters. We could modify constructor so it accepts not only name, but also color:
In some cases this would be a good approach, in other cases, not so much. Sometimes you might need an additional method or want to stop repeating yourself. In other words, you’d need something just like Cat, but…
Extensive extensions
At some point you might find yourself in need of defining some kind of superset for your existing classes.
A real-life example of this could be breeds: cats of all breeds have common cat features (eg. tail, ears, meowing). They can also have some additional, breed-specific features that are universal, but within the breed.
For instance, the dictionary definition of a Persian cat (they come in many colors, but for the sake of brevity, let’s just pick red) could be as follows:
So in JS, with our Cat defined as:
…the Persian cat could be:
See that extends keyword? This means we take the Cat class and create Persian on top of it. You can add new methods (eg. purr() {…}) and override existing ones (as we did with fur, which was not the best practice, but does a good job to illustrate the matter). You can refer to the base class (Cat) using the super keyword (see constructor and fur).
Apart from that, notice one more fun ES6 syntax — the three dots, called spread operator. In this case, it causes the fur method to return a new object that contains all the properties of defaultFur, and has the isLong property, which is set to true. Some other spread operator examples can be found here.
Back to cats, creating a new instance of Persian looks like this:
And it speaks, as expected:
Refactor Required
Both in terms of making sense and code quality, our Cat and Persian classes present a lot of room for improvement. We’ll draw a veil over the first issue, but we should definitely tackle the latter.
Getter
Did you catch me writing “Good practice [of naming methods] is using the verb of imperative mood” and then calling one earsAmount()? Aren’t you observant! Let’s fix the code now.
As earsAmount does not take any arguments and it is a kind of property rather than an action, it would be good to treat it like one.
Let’s try changing:
…to:
In this case it doesn’t make that much of a difference, but I guess you can imagine a situation where some computation would have to be done before returning something. Nonetheless, now we can access earsAmount as if it was a regular property (without the brackets):
Setter
While we’re at it, setter is another syntax worth mentioning. It allows you to bind a property to a function, which gets called when assigning a value to that property. In our case, the example will be kind of forced, but you get the idea:
Field
In the wild wild west of JS, it is common to use features that aren’t official yet. For instance, setting class fields with ‘=’ is still a proposal, but with a plugin can be used as follows:
Static
Some properties (or methods) can be specific for a class, but have nothing to do with its instances. In JS they can be defined as static (note how latinName is called without creating any instance):
Bottom Line
JS classes are primarily syntactical sugar over JavaScript’s existing prototype-based inheritance (MDN, some in-depth read here).
This article was intended to shed some light on the matter and make this increasingly popular notation legible to the less experienced.
So please keep in mind that:
TL;DR
- Class definition is a blueprint that describes properties of created objects
- Class instance is an incarnation of that blueprint (created by calling new Classname();)
- Class can extend some other class (class Second extends First {…})
- Class method can be a constructor, a getter, a setter, static or a plain, regular one
If you found this article classy and/or you’d like to show the love for cats, don’t hesitate and hit some 👏!
About the Author
Joanna is a Frontend Developer at EL Passion. You can find her on LinkedIn.
Find EL Passion on Facebook, Twitter and Instagram.