It’s no secret that programming languages will implement features from other programming languages when
it’s a smart solution for a problem (did I just hear you say async/await?) or if the feature is really useful
and generally nice to have.
That is why today we’ll be talking about decorators, how they fit in JavaScript and we’ll be going over a simple example.
Decorators are currently a stage 2 proposal which means they’re still not in JavaScript but probably will be in the future.
While decorators don’t solely exist in Python we’ll be looking at their definitions and explanations since JavaScript decorators will (probably) look a lot like Python decorators. (It also helps that I’m a huge fan of Python and think it’s the most baller programming language after JavaScript).
What is the decorator pattern?
In object-oriented programming, the decorator pattern (also known as Wrapper, an alternative naming
shared with the Adapter pattern) is a design pattern that allows behavior to be added to an individual
object, either statically or dynamically, without affecting the behavior of other objects from the same class.
The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows
functionality to be divided between classes with unique areas of concern.
Definition taken from Wikipedia. (Link)
So what does Python say decorators are?
A decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it.
Definition taken from Primer on Python Decorators. (Link)
The gist of it
Decorators take one thingy and make it better by adding logic from another thingy.
Apologies for the scientific terminology, sometimes you just can’t get around using it…
Python decorator example
This is what decorators look like written in Python:
Example taken from Wikipedia. (Link)
def viking_chorus(myfunc):
def inner_func(*args, **kwargs):
for i in range(8):
myfunc(*args, **kwargs)
return inner_func
@viking_chorus
def menu_item():
print("spam")
Don’t think too much about the code if you’re not into Python. The only interesting part up there for us is the @viking_chorus
The above code translates to:
def menu_item():
print("spam")
menu_item = viking_chorus(menu_item)
As you can see the decorator is basically just a cool kid’s way of calling higher-order functions, which
is beyond easy in JavaScript, although if not used correctly can get quite ugly.
JavaScript isn’t trying to tackle this non-problem instead it’s setting its sights on something else — classes and class members (properties).
Imagine you have multiple classes that need to share the same chunk of functionality or in multiple classes you
need to modify certain properties the same way.
Inheritance is nice but it can only get you so far, in these cases the usefulness of decorators becomes apparent.
JavaScript decorator example
Lets look at a really simple example of a JavaScript decorator, one you’ll most likely find floating on the internet — a class member decorator that modifies a class property.
function readonly(target, name, descriptor) {
descriptor.writable = false;
return descriptor;
}
class Job {
@readonly
title() { return 'CEO' }
}
What the code above does is modify the title
property so it can’t be reassigned, making it readonly
See how I named the decorator ‘readonly’ and it modifies properties so that you can only read them? That’s years of software development experience right there, baby!
You’re probably wondering what are all those function arguments, so lets go over them:
target — class that the property is a part of
name — the name of the property the decorator is modifying
descriptor — property descriptor. Think: object passed to Object.defineProperty
From the example above we can see that not only do decorators make the code cleaner but also sharing bits of common logic across class properties becomes incredibly easy.
Which is the whole point of decorators.
Angular 2
I’m mentioning Angular 2 here because Angular 2 uses Typescript, Typescript supports decorators and they’re used heavily in Angular 2.
I’ve been working on an Angular 2 project for a while now and kinda stopped noticing decorators, they just
become mundane but when you start noticing them again you see how much nicer the code is because of them.
Angular 2 decorator example
Lets look at how you create a component class and decorate it in Angular 2
@Component({
selector: 'example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent { ... }
That’s a really cool way of adding metadata to a component class.
Selector
is the html tag angular will use to render this component (<example></example>
)
templateUrl
is the html for this component
styleUrls
is a list of css styles the component will use
@Component
is a great example of sharing common functionality between classes.
Something that would’ve been a royal pain in the ass without decorators is cleanly and simply handled with decorators. Nice!
React
React is a prime candidate to start using decorators since its higher-order components are higher-order functions
that return components.
In fact, decorators are such a good fit with React that react-dnd, the most popular React drag and drop
library, is already using them! (Link)
Takeaway
JavaScript decorators are still not officially supported but they’re going to be soon and developers that
take the time to study up on them will be in a much better position than the ones who don’t.
My advice is to check out how they’re used in other languages because that’s probably how you’ll be using
them in JavaScript, maybe even experiment and create your own decorators that abstract away common shared class or
class property logic!