DEV Community

Cover image for JavaScript Functions: Why They're Essential to Understand? | Easy Guide - Part2
Ahmed Radwan
Ahmed Radwan

Posted on • Originally published at nerdleveltech.com

JavaScript Functions: Why They're Essential to Understand? | Easy Guide - Part2

We looked at what functions are and the different types of declarations. We also looked at parameters, scope, hosting, and creating methods. Please refer back to JavaScript Functions part one for any of the above topics and more if you want to understand this blog post better.

Table of Content:

Arrow to the right
Arrow to the right

Arrow Functions

What are arrow functions?

Arrow functions are a different way of writing a function expression, and a shortcut to writing an anonymous function. For the next example, we'll have an expression function and convert it to an arrow function:

let nerd = function(level) {

  return level + " level"

}

console.log(nerd("nerd"))

//output: nerd level

Now by converting it to an arrow, notice what we will do in the next lines:

let nerd = (level) => {

  return level + " level"

}

console.log(nerd("nerd"))

//output: nerd level

We rid of the keyword function and we could also rid of the parentheses if the parameters only one parameter and if the function only returns one statement you can get rid of the keyword return and the Curly brackets like:

let nerd = (level) => level + " level"

console.log(nerd("nerd"))

// output: nerd level

Because you can’t use this keyword with an arrow function, still you can shorthand the function inside an object. Basically, you get rid of the “:“ and function keyword.

const nerdsInfo = {

  social: {

    blog: "nerdleveltech.com",

    twitter: "twitter.com/NerdLevelTech",

    reddit: "www.reddit.com/user/NerdLevelTech"

    },

      printSocial () {

      console.log(`Social links: 

      ${this.social.blog} 

      ${this.social.twitter}

      ${this.social.reddit}`)

    } 

}

nerdsInfo.printSocial()

// output: Social links: 

//     nerdleveltech.com 

//     twitter.com/NerdLevelTech

//     www.reddit.com/user/NerdLevelTech

Things to keep in mind regarding arrow functions:

  • The arrow functions do not have their own binding to the “this“ keyword
  • The Arguments array-like object is not available with the arrow function
  • You can use the “rest“ operator to get to the arguments

lego constructor
lego constructor

Constructors

What are constructors?

You can create reusable objects in more than one way. So let's explore another popular pattern for creating them called the constructor pattern. The constructor is a way to write classes with JavaScript functions. We can also say the following

Its JavaScript functions act like classes:

let Nerd = function (){

  let level;

}

let firstNerd = new Nerd

firstNerd.level = "Vito"

console.log(firstNerd)

In this above example, we start the first letter big, as it’s a familiar thing with this pattern. notice also “let firstNerd = new Nerd“ that’s name an instance of the class named Nerd accessing the property inside the Nerd function that acts like a class.

Speaking of the properties, JavaScript has an access to a very special type of property called a prototype. Using the example above but adding a value to the property prototype:

let Nerd = function (){

  let level;

}

Nerd.prototype = {

  study: function(what) {

    return (console.log(what))

  }

}

let firstNerd = new Nerd

firstNerd.level = "Nerd"

firstNerd.study("JS")

console.log(firstNerd.level)

//output: JS Nerd

Or we can use the prototype "sound" separately with the animal's classes example, like in the following example:

//Now we create two pets
let sound = function(hear) {

  return (console.log(hear))

}

let Dog = function() {

  let name;

}

let Cat = function() {

  let name;

}

Dog.prototype.sound = sound
Cat.prototype.sound = sound

// let’s create the Dog instances: 

let myDog = new Dog

myDog.name = "Jojo"

myDog.sound = "woof"

// let’s create the Cat instances: 

let myCat = new Cat

myCat.name = "Gogo"

myCat.sound = "meaw"

console.log(myCat, myDog)
// output: Cat { name: 'Gogo', sound: 'meaw' } Dog { name: 'Jojo', sound: 'woof' }

Things to keep in mind with the constructors:

  • Notice that we repeated some properties like name on both functions Cat and Dog. You can consider having a higher function called pet or animal that has this name, then inherit it, so you don't repeat yourself.
  • Now that this has happened, you'll face another challenge with more extensive systems. Getting all the objects and properties right up front will complicate your design process.

Multiple pieces of woods
Multiple pieces of woods

Modules

What Are modules?

The Modules are library code bases that let you store the function or functions you need into a file. That file can be imported and exported with your project or across different projects. Now with this imagine how organized your code will be instead of repeating your code throughout your project and all your different other projects.

How to write modules?

The way we write modules has changed for the better with the recent JavaScript version. All you need to do is write the functions and use the keyword export before the keyword function.

export function add (...args){

  return args.reduce(function(a,c) {

    return a + c

    })

}

Let’s say we created a file with this above function called modTest.js

Now we can go and import it inside another file:

import { add } from "./modTest.js"

We use the destruction above, so we can import as many functions as we want from that file. Although it's only one function, you need to get used to the syntax with a non-default export function. e.g. export default function add (...args) {}

or

import addSum from "./modTest.js" notice that you named it with a different name when imported, that change should happen according to your name convention.

or

import {addSum as sumAdd} from “./modTest.js“ - destructing and change the name

or

import * as funcs from “./modTest.js“ The asterisk means all the functions within the prefix of funcs, and now you could use this syntax to call the functions with it like that: “funcs.add”

Things to keep in mind about Modules:

  • With Modules, you create local variables within that code base without polluting your main code

Friends show closure gif

Closures

What is closure?

Closures use certain aspects of scope in JavaScript, remember the scope refers to the availability of variables in your code. There is a certain type of scope called lexical scope. which is an inner function that gets access to a parent's scope resources and variables.

The closure is created by JavaScript when you use a function or the keyword “function“ inside another function. Here, the child function (or any other function within the parent) can access the parent's variables and the parent's variables can remember the environment that was created and any changes that were made to its values from the child function. Have a look here at this example, it goes like that:

function counter() {

  let num = 0

  return function() {

    console.log(num++)

  }

}

let numbers = counter()

numbers() // 0

numbers() // 1

numbers() // 2

That counter function has an internal function that we call (Closure) Why? because it used the keyword “function” inside it. That allows the variable to remember the value of “num”, in the parent function. Although we have increased and returned it inside another function. But JavaScript kept its value updated every time you run the function.

In the next example. The object will have two methods. We call them methods because they are functions inside an object.

function myCounterObj() {

  let num = 1

  return {

    show: () => console.log(num),

    increment: () => num++

  }

}

let myNum = myCounterObj() //creating instance

myNum.show() // 1

myNum.increment() // incremented by ++ 

myNum.show() // 2

myNum.increment()

myNum.show() // 3

Neon red lights
Neon red lights

Recursion

What is recursion?

Recursion happens whenever a function call itself, of course, that raises the question of how we stop the function, and what if the function kept calling itself indefinitely?

This is when we need to put a stop condition if met the recursion stops. We call that the “base case”. Or we can pass an argument as the number limit of how the function should call itself, like in the Fibonacci example below:

// Without a base case

function itself() {

  itself()

}
// With a base case

function increment(number, maxNumber) {

  if (number > maxNumber) return

  console.log(number)

  increment(number+1, maxNumber)

}

increment(1, 10)

In the next example one of the most popular interview questions for functions to build a Fibonacci sequence, and will have the solution using the recursion technique:

let fib = function(count) {

  if (count === 1) return [0, 1] // the base case

  let arr = fib(count -1)

  let sum = arr[arr.length -1] + arr[arr.length -2]

  arr.push(sum)

  console.log(arr)

  return arr

}

fib(7) // the function will be called 7 times according to the variable “count” value.

// output: 

// Fib: 7

// Fib: 6

// Fib: 5

// Fib: 4

// Fib: 3

// Fib: 2

// Fib: 1

// arr:

// [ 0, 1, 1 ]

// [ 0, 1, 1, 2 ]

// [ 0, 1, 1, 2, 3 ]

// [ 0, 1, 1, 2, 3, 5 ]

// [ 0, 1, 1, 2, 3, 5, 8 ]

// [ 0, 1, 1,  2, 3, 5, 8, 13 ]

// So as we can see the recursion works as a backwards loop by looking at the fib value each time

Airplanes show
Airplanes show

Asynchronous Functions

What are asynchronous functions?

Functions that wait for certain conditions or things to happen, You can build a function that only works when something else triggers it. In JavaScript, we can create this kind of function using the keywords “Async / Await“

Another expression is called promise, which is that a certain condition needs to be done, met, or returned first to trigger the function to run or complete, we mentioned that part above.

async function canDo() {

  return console.log("Currently doing it...")

}

canDo().then (task => {

  console.log("yes you did it!")

})

// output: 

// Currently doing it...

// yes you did it!
async function doIt() {

  return console.log("Preparing it...")

}

async function canDo() {

  await doIt()

  return console.log("Currently doing it...")

}

canDo()

// output: 

// Preparing it...

// Currently doing it...

Although we call the canDo() function, the first string printed was the string in the doIt() function, why?

Because we had to wait for the doIt() function to happen before we could run the rest of canDo() function’s statements and return it.

The most practical use of async/await inside JavaScript is fetching data from an external source. Once the data is fetched, the promise is fulfilled.

async function getSocial() {

  // Once the data received then the promised fulfilled.

  const result = await fetch("https://links.socialData.json") 

  const data = await result.json() 

  return data

}

async function printSocial() {

  try{

    const social = await getSocial()  

    console.log(social)

  } catch {

    console.log("Error: the data not available")

  }  

}

printSocial()

// output:

// Error: the data not available

We tried to fetch from a non-existing URL to demo the try/catch statement as well. if any error happens we could see what we do with it by using try{} and catch{}.

try{

// any code you want to work

} catch {

// if it didn’t work, do the following with the error you caught

}

Conclusion word in separate characters
Conclusion word in separate characters

Conclusion Why functions are essential to understand?

Functions can be applied in a variety of ways. By writing them in these chunks of code, you're not only organizing your code, you're also saving yourself a ton of time by not repeating yourself with the same functionality in case you want it again in your project. And believe me, you will.

The more you practice and explore functions the more you achieve to write concise and clean code that can save you time and money. Take a look at these great resources on functions:

Top comments (0)