I'm in my Functions era

A review of JavaScript functions (and pasta recipes)

Several years ago, I tried learning JavaScript on my own. I signed up for an online course, and it felt promising for about 5 minutes until I stumbled on functions. It didn't make sense:

function helloWorld() { console.log("Hello, world!"; }

helloWorld();

I was embarrassed because it seemed like something coders just knew. So when I got access to Ada (Flatiron's AI assistant that answers programming-related questions), I asked her the question that had been on my mind all these years: what are those empty parentheses for??

Ada explained that "empty parentheses in code typically indicate a function or method call". It finally dawned on me that there is a difference between defining a function and calling (invoking) it. It sounds so obvious, but I had no clue!

From then on, I became an afunctionado, but I got a little carried away with functions at first. In the first few code challenges, I wanted to write a new function for everything. "You mean to tell me I can abstract a segment of code for reusability?! Sign me up!"

I eventually calmed down and now use them thoughtfully. So now that I'm about finished with Phase 1 of the bootcamp, I thought we could take a look back at Functions, and appreciate just how far we've come in this journey.

So what exactly is a function?

W3Schools defines a function as "a block of code designed to perform a particular task". In other words, a function contains a collection of instructions. If that sounds too vague and abstract, that's because it is! (Functions are abstractions, after all.)

To put it into more concrete terms, let's use a pasta recipe as a metaphor:

1. In a large pot, bring water to a boil.
2. Add pasta to the pot, and add salt to taste. 
3. Let it cook for 10 minutes.
4. Drain and serve with sauce.

Since a recipe is a set of instructions, here's how we could define it as a function:

function cookPasta(pasta, cookTime) {
    water.temperature = 100°C;
    cook pasta for cookTime;
    add.salt;
    drain.water;
    serve;
};

In this function definition, we are saying that this recipe takes a pasta type and the recommended cookTime. These are the function's arguments. With the recipe function in hand, we can now execute it with any type of pasta:

cookPasta(spaghetti, 10);
cookPasta(rigatoni, 12);

When we defined the recipe function, the first argument in the parentheses was pasta. So when we call (invoke) the function, we can pass a type of pasta as the first argument. Computers don't inherently know their spaghetti from their rigatoni, but by passing it in order as the first argument in the function call, we are saying "use spaghetti as the pasta" or "use rigatoni as the pasta".

All this pasta talk got me hungry!

How to write functions

If we need to give a function a name (to be called later), we can use a function declaration. For example:

// Function declarations take a name:
function cookPasta(arg1, arg2) { 
    // code 
};

Function expressions are similar to function declarations, except that they don't take a name.

// Function expressions can be anonymous:
function () { console.log("I love pasta!") };

Adding () at the end of a function expression makes it self-invoking. Gotta admire the self-reliance!

// Function expressions can be self-invoking:
( function () { console.log("I love pasta!") })();

Arrow function expressions allow us to further simplify our syntax:

function (pastaType) { console.log(`I love ${pastaType}!`);};

// Replace "function" with => to indicate an arrow function:
(name) => { console.log(`I love ${pastaType}!`);};

// Simplify syntax by removing parentheses and curly brackets:
name => console.log(`I love ${pastaType}!`);

Functions can also take other functions as arguments. These argument functions are referred to as "callback functions":

// Define a cookPasta function that takes in the pastaType,
// cooktime, and a callback function:
function cookPasta(pastaType, cookTime, callback) {
    const cookedPasta = pastaType.cook() for cookTime;
    const pastaWithSauce = cookedPasta + callback;
};

// Define a makeSauce function with two ingredients:
function makeSauce(ing1, ing2, ing3) {
    const sauce = ing1 + ing2 + ing3;
    return sauce;
}

// Invoke cookPasta with makeSauce(tomato, onions) as 
// callback argument:
cookPasta(spaghetti, 8, makeSauce(butter, garlic, lemon));

And that's that on the fundamentals of writing functions. Thanks for reading!

Bruno


Sources:

W3Schools: JavaScript Functions

Cornell.edu: Abstraction

MDN: Functions

Arrow function expressions

MDN: Callback function