Categories
Functional Javascript

Functional JavaScript — Functional Programming and Arrays

JavaScript is partly a functional language.

To learn JavaScript, we got to learn the functional parts of JavaScript.

In this article, we’ll look at how to create our own array methods.

Working Functionally on Arrays

Array functions are useful for manipulating arrays.

There are many built-in array methods like map and forEach .

Many of them take callbacks which let us do something with the array entries.

map

The map method lets us convert array entries from one thing to another.

To implement it, we can loop through each entry and call a function that we pass in.

The function’s returned value will be pushed into a new array and returned.

For example, we can write:

const map = (array, fn) => {
  const results = []
  for (const a of array) {
    results.push(fn(a));
  }
  return results;
}

The map function takes an array and fn function.

We use the for…of loop to loop through the entries.

fn is used to map a value from one to another value.

Then we push the returned item in the results .

And we return the results array.

Then we can use it by writing:

const arr = map([1, 2, 3], (x) => x ** 3);

Then arr is:

[1, 8, 27]

filter

We can implement our own filter function which lets us return a new array with entries that meets a given condition.

The condition is in the callback.

For example, we can write:

const filter = (array, fn) => {
 let results = [];
  for (const a of array) {
    if (fn(a)) {
      results.push(a)
    }
  }
  return results;
}

We loop through the array with a for…of loop.

Then we check with the fn function with the argument a whether it returns true or not.

If it returns true , then we push the item a into results .

Once we looped through all the items, we return results .

Then we can use it by writing:

const arr = filter([1, 2, 3], a => a % 2 === 1);

Then we get:

[1, 3]

as the value of arr .

Chaining Operations

We can chain the 2 operations since they’re both pure functions.

For instance, we can filter our items and then map them to the values of our choice:

const map = (array, fn) => {
  const results = []
  for (const a of array) {
    results.push(fn(a));
  }
  return results;
}

const filter = (array, fn) => {
  let results = [];
  for (const a of array) {
    if (fn(a)) {
      results.push(a)
    }
  }
  return results;
}

const arr = map(filter([1, 2, 3], a => a % 2 === 1), a => a ** 3);

We first called the filtet function to return an array of odd numbers.

Then we cube all the odd numbers and return the array of cubed odd numbers.

So arr is:

[1, 27]

We can rewrite that in a cleaner way by writing:

const odd = filter([1, 2, 3], a => a % 2 === 1);
const arr = map(odd, a => a ** 3);

Conclusion

We can create our own map and filter functions to map array entries and return a filtered array.

Categories
Functional Javascript

Functional JavaScript — Functional Array Methods

JavaScript is partly a functional language.

To learn JavaScript, we got to learn the functional parts of JavaScript.

In this article, we’ll look at how to create our own array methods.

concatAll

We can create our own concatAll method to concatenate all the nested array into one big array.

For example, we can write:

const concatAll = (arrays) => {
  let results = []
  for (const array of arrays) {
    results = [...results, ...array];
  }
  return results;
}

We just spread the array entries of all the arrays and then return the resulting array.

Then we can use it to unnest nested arrays.

For example, we can write:

const arr = concatAll([
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
]);

Then arr is:

[1, 2, 3, 4, 5, 6, 7, 8, 9]

Reducing Function

Reduce is a function that lets us combine the entries of an array into a single value.

To create our own reduce function, we can write:

const reduce = (array, fn) => {
  let accumlator = 0;
  for (const a of array) {
    accumlator = fn(accumlator, a)
  }
  return accumlator;
}

The reduce function takes an array and a fn function.

array is the array we loop through to combine the values from the array and assign it as the value of accumulator .

fn returns a value with the accumulator and a values combined into one with some operations.

Once we looped through the array, then we return the accumulator value.

Then we can use it to add the numbers in the array by writing:

const sum = reduce([1, 2, 3, 4, 5], (acc, val) => acc + val)

We pass in a number array and a callback to combine the entries of the array together.

Then sum is 15 since we added all the numbers together.

We can make the reduce function more robust by accepting an initial value for accumulator .

For example, we can write:

const reduce = (array, fn, initialValue) => {
  let accumlator = initialValue;
  for (const a of array) {
    accumlator = fn(accumlator, a)
  }
  return accumlator;
}

We assign the initialValue as the initial value of accumulator .

This way, we don’t assume that we’re always working with number arrays.

Zipping Arrays

We can zip multiple arrays into one.

We create the entry for each array with our own function.

And then we push that into the array we return.

We only loop up to the length of the shortest array, so the returned array will also have the same length as the shortest array.

For example, we can write:

const zip = (leftArr, rightArr, fn) => {
  let index, results = [],
    length = Math.min(leftArr.length, rightArr.length);
  for (index = 0; index < length; index++) {
    results.push(fn(leftArr[index], rightArr[index]));
  }
  return results;
}

We created a zip function with the leftArr , rightArr , and fn parameters.

leftArr and rightArr are arrays and fn is a function.

We loop through the shortest length, which is the length .

In the loop body, we push the zipped entry to the results array.

Once we did that, we return results .

Then we can use that by writing:

const zipped = zip([1, 2, 3, 4], ['foo', 'bar', 'baz'], (a, b) => `${a} - ${b}`)

We have a callback to combine the entry from the left and right together into a string.

Then zipped is:

["1 - foo", "2 - bar", "3 - baz"]

Conclusion

We can unnest arrays and zip them together with our own functions.

Categories
Functional Javascript

Functional JavaScript — Currying

JavaScript is partly a functional language.

To learn JavaScript, we got to learn the functional parts of JavaScript.

In this article, we’ll look at how to use currying with JavaScript.

Unary Function

A unary function is a function that takes a single argument.

For example, a unary function is:

const identity = (x) => x;

Binary Function

A binary function is a function that takes 2 arguments.

An example of one is:

const add = (x, y) => x + y;

Variadic Function

A variadic function is a function that takes a variable number of arguments.

We can define a variadic function in JavaScript by using the rest operator:

function variadic(...args) {
  console.log(args)
}

args has an array of all the arguments we pass in.

Currying

Curry is converting a function with multiple arguments into nested unary functions.

This is useful because it lets us create functions with some of the arguments applied.

For example, we can convert a binary function:

const add = (x, y) => x + y;

into a function unary function that returns another unary function by writing:

const addCurried = x => y => x + y;

The addCurried function takes a parameter x and returns a function that takes a parameter y which returns the sum of x and y together.

Then we can use it by writing:

const add1 = addCurried(1);
const sum = add1(2);

We called addCurried with 1 to return a function with x set to 1 and assign that to the add variable.

Then we call add1 with 2 to return the final sum.

We can generalize this by creating a function that returns a function that takes one argument, which is the binary function.

Inside that function, we return a function that takes the 2nd argument.

And inside that, we return the result of the binary function called with the parameters of the outer functions.

For example, we can write:

const curry = (binaryFn) => {
  return (firstArg) => {
    return (secondArg) => {
      return binaryFn(firstArg, secondArg);
    };
  };
};

const add = (x, y) => x + y
const sum = curry(add)(1)(2);

to create the curry function to do what we described.

Then we can pass in any binary function like our add function.

And then it’ll be curried automatically.

We can generalize this further with a curry function that recursively returns functions with one argument, until there’s only one argument left.

For instance, we can write:

let curry = (fn) => {
  if (typeof fn !== 'function') {
    throw Error('No function provided');
  }

  return function curriedFn(...args) {
    if (args.length < fn.length) {
      return function(...moreArgs) {
        return curriedFn(...[...args, ...moreArgs]);
      };
    }
    return fn(...args);
  };
};

We check if fn is a function.

If it is, then we return a function that returns a function that calls the same function that’s returned if fn has more parameters than args .

If there are more arguments in fn than args , that means that we can curry it more.

If the number of parameters of the curried function is the same as the number of parameters in fn , then we can’t curry more.

So we just call the function.

Then we can call it by writing:

const add = (x, y, z) => x + y + z;
const sum = curry(add)(1)(2)(3);

We curried the function, so we call the curried function with their individual arguments.

And sum is 6 since we add all the numbers together.

Conclusion

We can curry functions so that we can create functions with some arguments applied and reuse that function for something else.

Categories
Functional Javascript

Functional JavaScript — Creating Functions

JavaScript is partly a functional language.

To learn JavaScript, we got to learn the functional parts of JavaScript.

In this article, we’ll look at how to use the functional programming features in JavaScript.

Pure Function Is a Mathematical Function

Pure functions are mathematical functions.

They exhibit all the same characteristics.

Given the same input, then return one output.

JavaScript and Functional Programming

JavaScript is partly a functional programming language.

It has some of the features, but it also allows us to program it in a non-functional way.

For instance, we can create a function in JavaScript that takes no arguments.

But functions are treated as first-class citizens.

So we can have higher-order functions.

JavaScript Functions

We can create a simple JavaScript function by writing:

() => "foo"

We created an arrow function, which is available only in ES6.

We can assign it to a variable by writing:

const foo = () => "foo";

Then we can call the function by writing:

foo()

Strict Mode

JavaScript has a strict mode to let us write better JavaScript code.

To enable strict mode, we can add the 'use strict' directive to add the make the code below it use strict mode.

For example, we can write:

"use strict";

const bar = function bar() {
  return "bar";
};

to enable strict mode.

It’ll stop us from writing bad code like creating global variables accidentally:

"use strict";

global = 'bad';

Multiple Statement Functions

We can write functions with multiple statements.

For instance, we can write:

const simpleFn = () => {
  let value = "abc"
  return value;
}

We have an assignment statement and a return statement to return the value.

Function Arguments

Functions can take arguments.

For example, we can write:

const identity = (value) => value

It takes a value and returns it.

ES5 functions are valid in ES6.

But it doesn’t work the other way around.

So we can’t use arrow functions in an ES5 only environment.

Functional Alternatives to Loops

We can rewrite loops in a functional way by abstracting out the loop body into its own function.

For example, instead of writing:

const array = [1, 2, 3];
for (const a of arr) {
  console.log(a);
}

We can write:

const forEach = (array, fn) => {
  for (const a of arr) {
    fn(a)
  }
}

Our forEach function has an array and fn parameters.

We loop through the array and call our function.

This way, we can abstract out our logic to the outside and pass it in.

If we use const , then we can’t assign a new value to forEach accidentally.

Conclusion

We can create functions to a functional way by creating functions that don’t reference things from the outside.

Also, we can abstract out logic into their own functions and pass them in.

Categories
Functional Javascript

Functional JavaScript — Closures

JavaScript is partly a functional language.

To learn JavaScript, we got to learn the functional parts of JavaScript.

In this article, we’ll look at how to use closures.

Closures

Closures are inner functions.

An inner function is a function within a function.

For example, it’s something like:

function outer() {
  function inner() {}
}

Closures have access to 3 scopes.

They include variables that are declared in its own declaration.

Also, they have access to global variables.

And they have access to an outer function’s variable.

For example, if we have:

function outer() {
  function inner() {
    let x = 1;
    console.log(x);
  }
  inner();
}

then the console log logs 1 because we have x inside the inner function and we access it in the same function in the console log.

The inner function won’t be visible outside the outer function.

We can also access global variables within the inner function.

For example, if we have:

let global = "foo";

function outer() {
  function inner() {
    let a = 5;
    console.log(global)
  }
  inner()
}

Then 'foo' is logged since inner has access to the global variable.

Another scope that inner has access to is the scope of the outer function.

For example, we can write:

function outer() {
  let outer = "outer"

  function inner() {
    let a = 5;
    console.log(outer);
  }
  inner()
}

We have the outer variable and we access it in the inner function.

Closure Remembers its Context

A closure remembers its context.

So if we use it anywhere, the variables that are in the function are whatever they are within the original context.

For example, if we have:

const fn = (arg) => {
  let outer = "outer"
  let innerFn = () => {
    console.log(outer)
    console.log(arg)
  }
  return innerFn;
}

Then the outer and arg variable values will be the same regardless of where it’s called.

outer is 'outer' and arg is whatever we passed in.

Since we return innerFn with fn , we can call fn and assign the returned function to a variable and call it:

const foo = fn('foo');
foo()

We pass in 'foo' as the value of arg .

Therefore, we get:

outer
foo

from the console log.

We can see that the values are the same even if we called it outside the fn function.

Real-World Examples

We can create our own tap function to let us log values for debugging.

For example, we can write:

const tap = (value) =>
  (fn) => {
    typeof(fn) === 'function' && fn(value);
    console.log(value);
  }

tap("foo")((it) => console.log('value:', it))

to create our tap function and call it.

We have a function that takes a value and then returns a function that takes a function fn and runs it along with the console log.

This way, we can pass in a value and a function.

Then we get:

value: foo
foo

logged.

The first is from the callback we passed in.

And the 2nd is from the function we returned with tap .

Conclusion

Closures are inner functions.

They have access to the outer function’s scope, global variables, and their own scope.

We can use it or various applications.