DEV Community

loading...

JAVASCRIPT ADVANCED FUNCTIONS FOR DUMMIES

Muhammad Muhktar Musa
javaScript enthuthiast
Updated on ・7 min read

The objective of this essay is to highlight the scope and use of advanced functions in javaScript. It is aimed at programmers who find it difficult to understand the concepts dealt with here. In this article, we are going to tackle advanced functions so that they can be really grasped and understood. The best way to do that is to practice them yourself then use the write up as a reference and as a guide. The topics covered are those that you will mostly see out in the wild.

SCOPE

Scope can be said to be the context in which values and expressions are visible and can be referenced. If a variable or other expression is not in the current scope then it is unavailable for use. Scopes can be layered in a hierachy so that child scopes have access to parent scope but not vice versa. Variables defined only within a function cannot be accessed from outside a function or within other functions.

Let us take a look at this function

function addTwenty(num) {
    var add = 20;
    return num + add;
}
console.log(add);
Enter fullscreen mode Exit fullscreen mode

image

As you can see in the image above, after running this, it throws a reference error. This is because the

var add = 20;

is bound by the scope of the function. It is not visible outside the function, When we try to access it from outside the function. This called a function scope.
Another type of scope is the global scope Let us take a look at the function below

var globalVar = 'i am global';
function consult(str) {
    return str + ' ' + globalVar;
}
console.log(consult('i am hungry'));
Enter fullscreen mode Exit fullscreen mode

image

Here we are setting a variable called globalVar outside any other scope. Then inside our consult function, we are accessing this globalVar variable. Looking at the image above, we can see that we have access to the globalVar variable. Every other scope within this module has access to the globalVar variable. It is often best practice to avoid setting variables in this manner if possible. We want to avoid other parts of our code accessing and changing values that are used elsewhere which can lead to unexpected behaviour.
Another type of scope is the Block scope. Let us take a look at the sample code below

if (true) {
    var x = 2;
}
console.log(x);
Enter fullscreen mode Exit fullscreen mode

image

We have 3 methods of declaring a variable which is var, let and const. let and const are block scope while var is not. What this means is that variables declared using the let and const keywords are bound to the block they are defined within while var is not. That is why the code in the image above worked. Since var is not a block scope, it is not bound by the block scope and it is visible within the console.log();
Let us run the let and const keywords to see what we mean

if (true) {
    let x = 2;
}
console.log(x);
Enter fullscreen mode Exit fullscreen mode

image

When we try to access the above code it throws a reference error. This is because let and const are block scope and are not visible outside the block when we try to access them. They are variables that are evaluated during run time and bound by the block scope.

CLOSURES

An important javascript concept is CLOSURES. Closures can be thought of as when a function runs and it gets executed. The function is never going to execute again though it will remember that there are references to those variables. The child scope is always going to have access to the parent scope. When we run the code below

const first = () => {
    const greet = 'Hi';
    const second = () => {
        alert(greet);
    }
    return second;
}
const newFunc = first();
newFunc();
Enter fullscreen mode Exit fullscreen mode

we executed the

first();
Enter fullscreen mode Exit fullscreen mode

function and assigned it to the

newFunc();
Enter fullscreen mode Exit fullscreen mode

above. It is going to remember that there are references to those variables alive in the memory

first();
Enter fullscreen mode Exit fullscreen mode

so that when calling the variable

newFunc();
Enter fullscreen mode Exit fullscreen mode

the memory can have access to the parent scope. In reality, the code block executed will look like

const newFunc = Const second = () => {
    alert(greet);
}
Enter fullscreen mode Exit fullscreen mode

The function second is what we are really returning here. We can see that the variable

const greet = 'Hi';
Enter fullscreen mode Exit fullscreen mode

is not within the scope of second here

const second = () => {
    alert(greet);
}
Enter fullscreen mode Exit fullscreen mode

What closure does is and it's a general rule in javascript is that the child scope which is

const second = () => {
    alert(greet);
}

Enter fullscreen mode Exit fullscreen mode

always has access to the parent scope. It's almost as if it remembers that there is references to those variables

alert(greet);
Enter fullscreen mode Exit fullscreen mode

so that the web browser remembers that the child scope needs the variable greet.
Even though

first();
Enter fullscreen mode Exit fullscreen mode

is never going to run again the web browser remembers the

const greet = 'Hi';
Enter fullscreen mode Exit fullscreen mode

In essence closures can be defined as when a function runs and the function is executed, it is never going to execute again. The function will remember that there are references to those variables in memory so that the child scope has access to the parent scope.
Think of it this way, that children always have access to the parent scope but parents do not have access to the children.

CURRYING

The next we are going to talk about is CURRYING. Currying is the process of converting a function that takes multiple arguments into a
function that takes them one at a time. let us take an example function to see what i mean. We have a function

const multiply = (a, b) => a * b;
Enter fullscreen mode Exit fullscreen mode

To Curry, we have to change the above function from a function that takes two parameters to a function that takes one parameter at a time
e.g

const curriedMultiply = (a) => (b) => a * b;
Enter fullscreen mode Exit fullscreen mode

Think of the arrows above as functions. Let us run the function and see what I mean

const multiply = (a, b) => a * b;
const curriedMultiply = (a) => (b) => a * b;
curriedMultiply(3);
Enter fullscreen mode Exit fullscreen mode

The above code returns a function that is

(b) => a * b;
Enter fullscreen mode Exit fullscreen mode

currying

which means running the code

const curriedMultiply = (a) => (b) => a * b;
Enter fullscreen mode Exit fullscreen mode

where the number 3 will be assigned to

(a) =>
Enter fullscreen mode Exit fullscreen mode

when we run the function, because it is a function inside a function it just returns

(b) => a * b;
Enter fullscreen mode Exit fullscreen mode

To make it work, we can say

const multiply = (a, b) => a * b;
const curriedMultiply = (a) => (b) => a * b;
curriedMultiply(3)(4);
Enter fullscreen mode Exit fullscreen mode

currying2

On running the above code we now get 12. Let me break it down. We created a function

const curriedMultiply
Enter fullscreen mode Exit fullscreen mode

that accepts a parameter

(a) =>
Enter fullscreen mode Exit fullscreen mode

and once the function is called it returns another function that accepts

(b) =>
Enter fullscreen mode Exit fullscreen mode

and the function multiply

a * b ;
Enter fullscreen mode Exit fullscreen mode

and the number 12 is gotten.
Now, why do we need to do this? We do this because it makes our code more extensible. For example, we can now do something like

const multiply = (a, b) => a * b;
const curriedMultiply = (a) => (b) => a * b;
const multiplyBy5 = curriedMultiply(5);
Enter fullscreen mode Exit fullscreen mode

currying3

so that anytime we want to multiply a number by 5 we will have a function that was created that always multiply things by 5.

COMPOSE

Another important concept in javascript is COMPOSE. Compose is the act of putting two functions together to form a third function where
the output of one function is the input of the other. It is a really advanced concept in javascript which takes some time to grasp but
once it is understood a programmer can do anything. Let us give it a go
Example

const compose = (f, g) => (a) => f(g(a));
Enter fullscreen mode Exit fullscreen mode

What is happening here? Looking at f and g, f is a function and g is a function because of the bracket. If we had a function that takes a num

const sum = (num) => num + 2;
Enter fullscreen mode Exit fullscreen mode

What we can do with compose is we can

compose(sum)(sum)(5);
Enter fullscreen mode Exit fullscreen mode

If the above code is run on a javascript engine we get 9 as the output. Let us take it one at a time

const compose = (f, g) => (a) => f(g(a));
const sum = (num) => num + 2;
compose(sum, sum)(5);
Enter fullscreen mode Exit fullscreen mode

compose

When we run the above function compose it returns

(a) => f(g(a));
Enter fullscreen mode Exit fullscreen mode

When it runs it says

(a)=>
Enter fullscreen mode Exit fullscreen mode

is 5. now the inner function

f(g(a));
Enter fullscreen mode Exit fullscreen mode

is run. Here g is sum so we have the code basically saying

f(sum(5));
Enter fullscreen mode Exit fullscreen mode

and sum from

const sum = (num) => num + 2;
Enter fullscreen mode Exit fullscreen mode

means get me a num and add 2 giving us

f(2+(5));
Enter fullscreen mode Exit fullscreen mode

which gives us 7, and now running the f function

sum(2+(5));
Enter fullscreen mode Exit fullscreen mode

and also sum here is num + 2 we get the number 9.

Conclusion

That was a whole ton of stuff. I want you to remember the keywords we just covered because, in advanced javascript, functions are really really important. You will hear these words a lot and you will find tools and libraries that use this heavily. You don’t need to know the definitions, all you need is to read a piece of code and understand what is going on beneath the hood. By understanding the step by step process of how a function works, when you encounter them in the wild, you will understand how everything works.

SIDE EFFECTS AND FUNCTIONAL PURITY

When we create a function and we give it an input with or without a parameter, the function returns either a value or an undefined. Side effects are any action that happens inside the function that we don’t really know anything about. It reads, writes, or reacts to an external variable without our control. This is a side effect. Let us take a look at an example

var a = 2;
function b() {
    a = 6;
}
Enter fullscreen mode Exit fullscreen mode

A value is declared and assigned outside the function and within the function, it is assigned another value. It tends to create a side effect because the function will affect the outside world. Remember we want to think of functions as their own universe and if it starts affecting the outside world it affects the value we may get. So it is good practice to avoid these side effects and by avoiding these side effects we have what is called functional purity.

Functional purity is a concept where we say in order to write really good programs, we want to avoid side effects and always want to return a value. By avoiding side effects and returning a value, we create deterministic code. Whereby no matter what we input into a function, it will return a value that will be the same. It is a key principle in avoiding bugs.

side effects

Discussion (0)