Deep Dive Into JavaScript Functions

Introduction

Functions are vital to any programming language. The concept of isolating and/or organizing small pieces of code into subroutines have many uses and values. Thereby, it has helped us structure medium to large programs, to reduce repetition, and modularize programs and/or subprograms from each other.

That’s why this article will tackle the JavaScript function in depth. Moreover, if you are coming from an object-oriented language like C#, Java, and/or C/C++ reading this article will definitely help you. One reason is because of my .NET background and the class-minded way of thinking when it comes to C# programming.

Table of Contents

What is a JavaScript Function?

Within the language of JavaScript, functions are objects. Objects? Yes, it is true. Let us see the proof below.

function laugh() {
    return "hahahahaha";
}

console.log(typeof(laugh)); //output: function
console.log(laugh instanceof Object); //output: true
console.log(laugh instanceof Function); //output: true

Let us see, what the ECMAScript language specification has to say regarding the JavaScript function. See the screenshot below or you can visit and see it here.

Acknowledging that a JavaScript function is an object. And, I know you are questioning, how does the JavaScript language distinguishes a function from an object? But before answering that, let me explain something. The JavaScript language defines many internal properties for objects, these internal properties are designated by a double square bracket “[[]]” notation.

What do these internal properties have got to do with JavaScript functions? These internal properties can distinguish a function from an object, and this property is [[Call]]. Moreover, this [[Call]] property is unique to functions and indicates that the object can be executed. Thereby, [[Call]] property is exclusive for functions. That’s why, when using the typeof operator it returns “function” .

Again, because functions are objects. And, they behave differently compare to other programming languages. Therefore, a good understanding of JavaScript function is imperative.

Defining A Function

Function Declaration

A function declaration begins with the function keyword, plus the name of the function. Lastly, the contents (also known as code block) of the function are enclosed in curly braces. Let us see an example below.

function smile(happythought1, happythought2) {
    
    return "My happy thoughts are " + happythought1 + " and " + happythought2;
}

Function Expression

A function expression doesn’t require a name after a function keyword. Moreover, these functions are considered anonymous functions because the function itself has no name. And, it is referenced by a variable or property name.

Let us see an example below.

const smileAgain = function (happythought1, happythought2) {
    return "My happy thoughts are " + happythought1 + " and " + happythought2;
};

The sample code above actually assigns a function value to the variable smileAgain. As you can see, the function expression is pretty similar to the function declaration, with one exception the missing name and the semicolon at the end. More of their difference at the hoisting section.

Arrow Function

Recently, the ES6 version of JavaScript has introduced the arrow function. And, characterized as “=>” (looks like an arrow to me!). Moreover, it gives us the ability to have a shorter syntax. Therefore, it behaves like the function expression but looks different because of the combinations of arrow operator and lambda expression.

Here are the things needed to remember about arrow functions:

  • It consists of zero or more parameters that surround within an open and close parenthesis also known as round brackets ().
  • It is followed by the => operator
  • After the arrow operator, it followed by a function body. Just remember, the body only needs to be enclosed by curly braces {} if there’s more than one expression. Therefore you can omit the curly braces if there’s only one expression.

See the snippet below.

//declarative function
function showFavoriteLanguage(language) {
    return `I love ${language}`;
}

//arrow function equivalent
const showFavoriteLanguage= (language) => `I love ${language}`;

In this section, let’s convert a function declaration into an arrow function. First, let’s define a function.

function getProductOfTwoNumbers(num1, num2) {
    return num1 * num2;
}

Second, convert it into an arrow function.

const getProductOfTwoNumbers = (num1, num2) => {
    return num1 * num2;
}

Looks like a function expression. Right? Want some style? We can remove the curly braces.

const getProuductOfTwoNumbers = (num1, num2) => num1 * num2;

Great! Looks good to me.

If you are curious, what if we only have one parameter? Let us see an example below.

//gets the first element in the passed array
const getFirstElement = (arr) => arr[0];

//squares the passed number
const squareNum = (num) => Math.pow(num, 2);

Function Hoisting

In the previous section, we have seen how to define a function. Moreover, we have seen how similar the function declaration & function expression but differs in some ways.

Function declarations are hoisted to the top. Thereby, you can define a function after it’s used in code without causing an error.

Let us see an example below.

console.log(chuckle()); //output: Hehehehe

function chuckle() {
    return "Hehehehe";
}

Remember that function hoisting happens exclusively for function declarations. One reason, the function’s name was identified in advance. While, function expression (including arrow function), can’t be hoisted because it is referenced only through a variable.

Attributes Of A First-class Function

This is what makes JavaScript functions powerful. Because the JavaScript language has first-class functions. And, according to MDN (Mozilla Developer Network):

“A programming language is said to have First-class functions when functions in that language are treated like any other variable. For example, in such a language, a function can be passed as an argument to other functions, can be returned by another function and can be assigned as a value to a variable.”

And, you can look it up here.

Here are some examples:

  • Assign a function to a variable.
//assign a variable to a function

const love = function () {
    return "I love JavaScript";
}

 //output: I love JavaScript
console.log(love());

//end of assign a varaible to a function
  • Add function to objects.
//add function to objects 

const sayHello = function (name) { 

    return "Hi! My name is " + name;
}

const customer = {
    name: "Jin Vincent N. Necesario",
    sayHello:  sayHello
};

let name = customer.name;

//output: Hi! My name is Jin Vincent N. Necesario
console.log(customer.sayHello(name));

//end of function to objects
  • Pass function to other functions as arguments.
//pass function as an argument 

function sayFavorite() {
    return "Hi! My Favorite programming language is ";
}

function favoriteLanguage(func1, language) {
    
    return func1() + language;
}

//output: Hi! My Favorite programminglanguage is JavaScript
console.log(favoriteLanguage(sayFavorite, "JavaScript"));

//end of pass function as an argument
  • Return function from another function.
//return a function 

function followYou() {
    return function () { 
        return "Your part of me I can't let go!!!";
    };
}          

const follow = followYou(); 

//output: Your part of me I can't let go!!!
console.log(follow());

//end of return a function

Function Signatures

Overloading

If you are coming from a static language like C#, Java, and/or C/C++ these languages support function overloading. And, it is the ability of a single-function to have multiple signatures. Moreover, a function signature is composed of a function name, the number of parameters, and the type of parameters the function accepts. However, within the JavaScript language functions don’t have signatures. Therefore, JavaScript lacks function overloading.

Let us try to see what happens when we try to declare two functions with the same name.

function giveLove(act){
    console.log(act);
}

function giveLove() {
    console.log("Trust your partner");
}

//output: Trust your partner
giveLove("Love and trust your partner");  

Based on the example we have, if you are coming from an object-oriented language you’ll be expecting that the output should be "Love and trust your partner". And, because JavaScript lacks overloading, it executed the function that doesn’t have a parameter. Thus, the output is "Trust your partner".

Parameters

Another concept to understand is that JavaScript functions can pass any number of parameters without causing an error. This is because function parameters are stored as an “Array-like Object” called arguments.

If you like to read more about array-like objects you can visit here.

Moreover, arguments can grow to contain a number of values. The length property determines how many values are present in that function. Lastly, arguments object is automatically available inside any function. Therefore, named parameters in a function exist essentially for convenience and don’t limit the number of arguments that a function can accept.

Let us see an example below.

function decidedToLove() {

    let len = arguments.length,
        messageResult = "",
        counter = 0;

    while (counter < len) {
        messageResult += counter === 0 ? arguments[counter]: `,${arguments[counter]}`;
        counter++;
    }

    return messageResult;
}

//output: I'm in love
console.log(decidedToLove("I'm in love"));

//output: Don't be mean,Leave my heart alone
console.log(decidedToLove("Don't be mean", "Leave my heart alone"));

//output: love,trust,appreciate
console.log(decidedToLove("love", "trust", "appreciate"));

Default Parameters

Default Parameters Prior to ES6

Prior to ES6, there was no clear way to assign default values to function parameters. Thereby, developers can check the parameters before assigning the default values to them.

Let us see an example below.

function yourAmazing(arg1, arg2, arg3) {
    
    arg1 = arg1 || "arg1";
    arg2 = arg2 || "arg2";
    arg3 = arg3 || "arg3";

    return `${arg1}, ${arg2}, ${arg3}`;
}

//using all the default values
//output: arg1, arg2, arg3
console.log(yourAmazing()); 

//using the last two default values
//output: my-first-argument, arg2, arg3
console.log(yourAmazing("my-first-argument"));

//using the last default value
//output: my-first-argument, my-second-argument, arg3
console.log(yourAmazing("my-first-argument", "my-second-argument"));

//sending all with values 
//output: my-first-argument, my-second-argument, my-third-argument
console.log(yourAmazing("my-first-argument", "my-second-argument", "my-third-argument"));

Let us see another example, this time checks if the argument passed is undefined or not.

function areYouAnAngel(arg1, arg2, arg3) {
    
    arg1 = arg1 === undefined ? 1 : arg1;
    arg2 = arg2 === undefined ? 2 : arg2;
    arg3 = arg3 === undefined ? 3 : arg3;

    return `${arg1}, ${arg2}, ${arg3}`;
}

//using all the default values
//output: 1, 2, 3
console.log(areYouAnAngel());

//using the last two default values
//output: my-first-argument, 2, 3
console.log(areYouAnAngel("my-first-argument"));

//using the last default value
//output: my-first-argument, my-second-argument, 3
console.log(areYouAnAngel("my-first-argument", "my-second-argument"));

//sending all with values 
//output: my-first-argument, my-second-argument, my-third-argument
console.log(areYouAnAngel("my-first-argument", "my-second-argument", "my-third-argument"));

Default Parameters ES6

Recently, the JavaScript language has a new syntax that can do a default parameter in an easier and elegant way. Hooray!

  • Example of default parameter
function myGifts(gift1 = "health", gift2 = "wealth", gift3 = "love") {
    return `${gift1}, ${gift2}, ${gift3}`;
}

//using all the default values
//output: health, wealth, love
console.log(myGifts());

//using the last two default values
//output: healthy body, wealth, love
console.log(myGifts("healthy body"));

//using the last default value
//output: healthy body, cash-flow, love
console.log(myGifts("healthy body", "cash-flow"));

//sending all with values 
//output: healthy body, cash-flow, family
console.log(myGifts("healthy body", "cash-flow", "family"));
  • Passing undefined value to your default parameter
function youAreGreat(talent1 = 'write', talent2 = 'speak', talent3 = 'code') {
    
    return `${talent1}, ${talent2}, ${talent3}`;
}

//using all the default values
//output: write, speak, code
console.log(youAreGreat());

//output: read and write, speak, code
console.log(youAreGreat("read and write", undefined, undefined));

//output: write, teach and speak, code
console.log(youAreGreat(undefined, "teach and speak", undefined));

//output: write, speak, write books
console.log(youAreGreat(undefined, undefined, "write books"));
  • Using an expression within your default parameter
function myCashGifts(gift1 = 1000, gift2 = 2000, gift3 = (Math.random() * (5000 - 1000) + 1000)) {

    return `Your total cash: $${gift1 + gift2 + gift3}`;
}

//note: the value is random the output should be different
//output: Your total cash: $4307.070424503042
console.log(myCashGifts());

Function Type

Again, JavaScript functions are objects. Therefore, functions have properties and methods just like other objects. Let us see what we can do with these properties and methods.

Function Properties

  • The length property determines the total arguments in a function.
  • The prototype property references the actual function object.

Let us see an example of function-properties.

function setGift(gift1, gift2) {
    
    return `My gifts this coming Christmas are ${gift1} and ${gift2}`;
}

//output: 2
console.log(setGift.length);

//output: object {}
console.log(setGift.prototype);

Function Methods

The this Object

All scope in JavaScript has a this object that represents the calling object for the function. For instance, within the global scope, this represents the global object (window). Moreover, once a function is called while attached to an object, the value of this is equal to that object by default. Therefore, you can reference this instead of directly referencing the object inside your method.

Let us see an example below.

function showFullName() {
    console.log(this);
    console.log(this.name);
}

const name = "Jin Vincent Necesario";

const person = {
    name: "Jin Necesario",
    showFullName: showFullName
}

const pet = {
    name: "Bruno",
    showFullName: showFullName
}

//this value is equivalent to window object
//output: Jin Vincent Necesario 
showFullName(); 

//this value is equivalent to person object
//output: Jin Necesario
person.showFullName();

//this value is equivalent to pet object
//output: Bruno
pet.showFullName();

Understanding the this value of functions is key to good object-oriented programming in JavaScript. Three methods that permit you to change the value of this and these are call, apply, and bind methods.

The apply() and call() methods are almost the same when you want to manipulate the value of this. The only difference is that apply() needs array-like objects, whereas call() needs to pass the object that acts as this and needed arguments. Let us see them one by one with examples.

The call() Method

function showFullName(caller) {
    return `Caller: ${caller} having a value of ${this.name}`;
}

window.name = "Jin Vincent Necesario";

const person = {
    name: "Jin Necesario"
}

const pet = {
    name: "Bruno"
}

//output: Caller: global, the window object having a value of Jin Vincent Necesario
console.log(showFullName.call(this.window, "global, the window object"));

//output: Caller: person variable having a value of Jin Necesario
console.log(showFullName.call(person, "person variable"));

//output: Caller: pet variable having a value of Bruno
console.log(showFullName.call(pet, "pet variable"));

The apply() Method

function showFullName(caller, param1) {

    return `${param1}. The caller: ${caller} having a value of ${this.name}.`;
}

window.name = "Jin Vincent Necesario";

const person = {
    name: "Jin Necesario"
}

const pet = {
    name: "Bruno"
}

//output: Hi!. The caller: global, the window object having a value of Jin Vincent Necesario.
console.log(showFullName.apply(this.window, ["global, the window object", "Hi!"]));

//output: Hello!. The caller: person variable having a value of Jin Necesario.
console.log(showFullName.apply(person, ["person variable", "Hello!"]));

//output: Good day!. The caller: pet variable having a value of Bruno.
console.log(showFullName.apply(pet, ["pet variable", "Good day!"]));


The bind() Method

If you want a new function instance whose this value is bounded to an object that you have provided. Let us see an example below.

const bike = {
    speed: 10,
    start: function () {
        return `${this.speed} Km/h`;
    }
};

const motorcycle = {
    speed: 40, 
    start: function () {
        return `${this.speed} Km/h`;
    }
}

let upgradeBike = bike.start.bind(motorcycle);

//output: 40 Km/h
console.log(upgradeBike());

Summary

In this post, we have discussed a number of concepts regarding JavaScript functions. We started by answering: what is a JavaScript function, how to define a function, why JavaScript is a first-class function. Lastly, we have looked at function signatures and function types.

I hope you have enjoyed this article, as I have enjoyed writing it. Stay tuned for more. Until next time, happy programming! Please don’t forget to follow/subscribe, bookmark, like, and/or comment. Cheers! And Thank you!