Filth Filth - 22 days ago 5
Javascript Question

Javascript Functional Programming | Functions

I'm experimenting with functional programming using an array of objects.

I want to understand if there is a better or cleaner way to execute a series of functions that takes values and updates variables based on conditions.

Like the use of the globally scoped variables, is this frowned upon? Is there anyway I could pass lets say the count of the number of dogs to the "updateDogsAmt" function? And so on...

Is there a better way I could have done this?

I have divided out these functions between what I think is updating the DOM and logic.

Demo: JSFIDDLE

const animals = [
{name: 'Zack', type: 'dog'},
{name: 'Mike', type: 'fish'},
{name: 'Amy', type: 'cow'},
{name: 'Chris', type: 'cat'},
{name: 'Zoe', type: 'dog'},
{name: 'Nicky', type: 'cat'},
{name: 'Cherry', type: 'dog'}
]

let dogs = [];
function getDogs() {
//return only dogs
animals.map((animal) => {
if(animal.type === "dog") {
dogs.push(animal);
}
});
}
getDogs();

let dogsAmt = 0;
function getDogsAmt() {
//get dogs amount
dogsAmt = dogs.length;
}
getDogsAmt();

function updateDogsAmt() {
//update dom with dogs count
let dogsHTML = document.getElementById('dogs-amt');
dogsHTML.innerHTML = dogsAmt;
}
updateDogsAmt();

let otherAnimals = [];
function getOtherAnimals() {
//return other animals count
animals.map((animal) => {
if(animal.type != "dog") {
otherAnimals.push(animal);
}
});
}
getOtherAnimals();

let otherAnimalsAmt = 0;
function getOtherAnimalsAmt() {
otherAnimalsAmt = otherAnimals.length;
}
getOtherAnimalsAmt();

function updateOtherAnimalsAmt() {
//udate dom with other animals
let otherAmt = document.getElementById('other-amt');
otherAmt.innerHTML = otherAnimalsAmt;
}
updateOtherAnimalsAmt();

Answer

In functional programming, functions are pure, which means:

  • They don't cause side-effects (they do not modify variables outside of their scope)
  • Given the same input, they produce always the same output

The functions you define are not pure, because they

  • modify variables outside of their scope
  • return different results, depending on the value of variables outside of their scope

So this function is impure:

let dogsAmt = 0;
function getDogsAmt() {
  // do something with dogs and modify dogsAmt
});

while this one is pure:

function getDogsAmt(dogs) {
  // do something with dogs and return dogsAmt
});
let dogsAmt = getDogsAmt(dogs);

Writing in a functional style makes it easy to reuse code. For example, in your example you only need one function for counting animals and updating the DOM, respectively:

const animals = [
  {name: 'Zack',type: 'dog'},
  {name: 'Mike',type: 'fish'}, 
  {name: 'Amy', type: 'cow'},
  {name: 'Chris', type: 'cat'}
];

function getDogs(animals) {
  //return only dogs
  return animals.filter(animal => animal.type === "dog");
}

function getOtherAnimals(animals) {
  //return other animals count 
  return animals.filter(animal => animal.type !== "dog");
}

function getAmt(animals) {
  //get number of animals in the array
  return animals.length;
}

function updateHTML(id, amount) {
  //update dom
  document.getElementById(id).innerHTML = amount;
}

updateHTML('dogs-amt', getAmt(getDogs(animals)));
updateHTML('other-amt', getAmt(getOtherAnimals(animals)));
<p>There are <span id="dogs-amt">0</span> dogs</p>
<p>There are <span id="other-amt">0</span> other animals</p>

Is it all pure?

One function in this code is still not pure! updateHTML takes two arguments, and always returns undefined. But along the way, it is causing a side effect (it updates the DOM)!

If you want to get around this issue of updating the DOM manually based on impure functions, i would recommend looking at libraries/frameworks like React, Elm, Cycle.js or Vue.js - they all make use of a concept called virtual DOM, that allows representing the entire DOM as a JS data structure and take care of synchronizing the virtual DOM with the real one for you.

Functional Programming in JavaScript

Functional languages (e.g. Haskell, Lisp, Clojure, Elm) force you to write pure functions and introduce many mind-bending concepts when your background is more in procedural or object-oriented programming. Personally, i found my way to functional programming through JavaScript, which might look like Java at first glance, but is has much more in common with Lisp when you take a closer look.

For your next steps in functional JavaScript, i would recommend to

  • use as less state in your scripts as possible (no more let)
  • understand and use functions on the Array prototype like map, filter, reduce ([see e.g. this article]), some, any, ...
  • write only pure functions, and be mindful about cases when that's not possible

After you got more comfortable with that, you can start tackling more advanced functional concepts (Higher-order functions, partial application, currying, immutability, monads, observables/functional reactive programming) bit by bit. Some interesting libraries in JavaScriptLand are