Declarative Programming with JavaScript
Adnan Babakan (he/him)
Posted on July 31, 2020
Hey there DEV.to community!
As you know, JavaScript is a pretty vast programming language. Meaning that it doesn't limit you to a specific paradigm, and you can implement almost every famous paradigm and go on with it.
This made me think about how we can go on with the declarative paradigm instead of imperative. In case you don't know what these words mean, here is a simple explanation: Imperative means you tell the compiler what you exactly want to happen, while in declarative paradigm you only specify what you want the result to be.
Declarative style is best followed in functional programming languages while it is pretty fun to follow this style in JavaScript.
Iteration through an array
Perhaps this sample will make it obvious for you what the difference between an imperative and a declarative paradigm is.
Usually what you'd do is to define a for
loop as below:
let n = [-9, 87, 72, 452, 32, -9]
for(let i = 0; i < n.length; i++) {
console.log(n[i])
}
This is called the imperative way. While by using forEach
prototype of arrays, it is possible to rewrite this in a declarative way:
let n = [-9, 87, 72, 452, 32, -9]
n.forEach(v => console.log(v))
Both these codes have the same result, but the second one looks cleaner and more readable. Isn't it awesome?
Array mapping
Mapping is the action of applying a specific function to every item inside an array resulting in a new array.
Here is the imperative way:
let n = [-9, 87, 72, 452, 32, -9]
let z = []
let doubleMinusOne = x => (x * 2) - 1
for(let i = 0; i < n.length; i++) {
z[i] = doubleMinusOne(n[i])
}
Now the z
variable holds an array of items doubled and subtracted by one from the n
array.
Here is how to do it declaratively:
let n = [-9, 87, 72, 452, 32, -9]
let z = n.map(v => (v * 2) - 1)
Very short and concise!
Array filtering
What if you wanted some items from an array matching a condition? Here is how you'd do it normally in an imperative way:
let n = [-9, 87, 72, 452, 32, -9]
let z = []
let lessThanFifty = v => v < 50
for(let i = 0; i < n.length; i++) {
lessThanFifty(n[i]) && z.push(n[i])
}
And the code below is the declarative counterpart:
let n = [-9, 87, 72, 452, 32, -9]
let z = n.filter(v => v < 50)
KABOOM!
Reduce
This is the most amazing method ever existed and is very powerful! As the name suggests this method reduces array to a single value.
What if you wanted to have the summation of the numbers inside an array? What you'd probably do is as below:
let n = [-9, 87, 72, 452, 32, -9]
let s = 0
for(let i = 0; i < n.length; i++) {
s += n[i]
}
Here is the magic of reduce
!
let n = [-9, 87, 72, 452, 32, -9]
let s = n.reduce((acc, v) => acc + v)
The first argument of the function that reduce
takes is called accumulation (or total) which holds the value of the previous value returned by the function. Each time we are adding the current value (second argument) to the accumulation.
The reduce
method is not limited to summation only, and you can do almost everything!
let n = [-9, 87, 72, 452, 32, -9]
let m = n.reduce((acc, v) => acc * v)
Here is another awesome example. Finding the maximum (or minimum) value inside an array is simply possible by a simple algorithm:
let n = [-9, 87, 72, 452, 32, -9]
let maximum = n[0]
for(let i = 1; i < n.length; i++) {
if(n[i] > maximum) maximum = n[i]
}
Although it is pretty simple, by using the reduce
function it is possible to rewrite it in a declarative way which makes it very short (and professional-looking as well xD)!
let n = [-9, 87, 72, 452, 32, -9]
let maximum = n.reduce((max, v) => v > max ? v : max)
let minimum = n.reduce((min, v) => v < min ? v : min)
Given that you have a two-dimensional array and you want to flatten it. Here is the imperative way using a for loop:
let n = [[-9, 87], [72], 452, [32, -9]]
let flatten = []
for(let i = 0; i < n.length; i++) {
if(Array.isArray(n[i])) flatten = flatten.concat(n[i])
else flatten.push(n[i])
}
And now again! The power of reduce
:
let n = [[-9, 87], [72], 452, [32, -9]]
let flatten = n.reduce((acc, v) => acc.concat(v), [])
The second argument passed to the reduce
method (the empty array) is for the reduce
method to know the initial value of the accumulation.
Hope you enjoyed this article!
Posted on July 31, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.