- We use prototypical inheritance. This is unusual coming from programming languages with classes, like C# or Python.
thiskeyword is confusing to developers from OOP because it doesn’t refer to the object that defines the function (block scope); it refers to the object that calls the function (function scope). This has its own advantage and disadvantages, but overall it’s just different.
As developers, we should be embracing these quirky concepts and using them to our advantage.
- Write functions without side-effects when possible to limit your problem space. (Limiting variables to as small a scope as possible isn’t exclusively functional programming, but it’s heavily reinforced in functional programming.)
- Stop writing loops: use declarative array methods (
some) to improve readability.
- When writing declarative methods, it can be useful to return a mutated version of
thisto create chainable methods. For example,
[1,2,3].filter(...).map(...)is a useful method chain that is permitted through returning a mutated
- Write functions that accept functions as arguments; this is the joy that makes
- Write functions that return functions; this is a useful Factory pattern.
I found the easiest way to get my head around promises was to implement them myself. When I realised that promises are essentially an array of functions that are called when an asynchronous request finishes, a lightbulb went off in my head!
There is a good tutorial from Node School around promises if you need a primer. It goes into more detail than is useful sometimes, but you can certainly say you know how to use promises if you have got through this: https://github.com/stevekane/promise-it-wont-hurt
- Want a module for mixing in functionality? How about a decorator? Both are simple: define a function that takes in an object and augments it with your extra properties and methods. At the end, spit your augmented object back out!
- Reflection is built in, using a suite of methods like
- You can avoid globals by encapsulating your script in a function (this has the catchy title of an Immediately Invoked Function Expression). This has the added benefit of isolating you from any globals that may have been defined elsewhere.
Good software engineering practices are there, you just have to look a little harder for them.
- You declare Angular elements on your modules as functions. These declarations can be chained.
- Promises are used for asynchronous calls.
- Angular doesn’t try to introduce concepts like classes or inheritance.
- Angular’s Dependency Injection provides the dependencies it needs to avoid side-effects from global objects.
- Scope variables are used to isolate state.
My excuse is no longer valid. And now you’ve read this, neither is yours!
This article was written by Jonny Arnold for Reevoo Engineering. Thanks to Cian Leahy for proof-reading and the entire Engineering Team for tolerating my going-too-fast lightning talk on this subject.