Welcome back Fam!
Today I wanted to create a blog to break down the different types of JavaScript functions in the most basic terms.
When I was first starting to code the MDN docs confused me most of the time, so this will be part of an ongoing series into the core fundamentals of JavaScript written by someone who didn't come from a CompSci background.
What is a Function
That's right, we need to start from the beginning!
A function is the very building block of coding, and whether it is JavaScript or Java you're going to want to get acquainted with the fundamentals of the fundamentals.
In JavaScript (like most languages) a function is a block of code that performs a task or returns a value, one good thing to note at this point is a function should do that, perform one function (but that's a debatable story for another time).
But to make it a bit more interesting, JavaScript has evolved and has quite a few different ways to declare and use them, so let's start.
Function Declaration
I will start with a Function Declaration because it comes first, and I mean that because a Function Declaration gets hoisted the moment the program is compiled.
Hoisting you ask? hoisting is the way JavaScript allocates functions to memory and in what order, and this is a topic worth exploring on its own and this article explains it well.
function funcName(withParams) {
// params can be declared, but are not enforced;
};
function funcName() {
// without declared params;
};
funcName();
Syntax:
- starts with 'function'
- followed by the name
- with optional params, if you don't declare params, you can still pass them though and they'll be accessed with arguments
- invoked by calling the function name
The reason a Function Declaration gets hoisted first is that as it compiles, JavaScript looks for the declarations starting with 'function', makes sense, huh, this then hoists all those declarations to the top of the pile.
This can lead to some gotcha moments though that we should be aware of, mainly that if a program is compiled and a Function Declaration gets invoked before the Function Declaration is hoisted.
Function Expressions
A Function Expressions is where an anonymous function is assigned to a variable(var/let/const)
const funcName = function() {
// do something;
};
funcName();
Syntax:
- starts with the name declared in a variable
- function() assigned to the variable
- params operate the same way
- invoked the same way
Function Expressions are not hoisted, so this would prevent those icky instances of a Function Expressions getting invoked before it gets hoisted and stashed in memory.
P.S. while Function Expressions are not hoisted the VAR declaration IS, so if you declare a function with VAR it will be hoisted.
But wait,
And it's called a Named Function Expression
const funcName = function yoda(){
// do something
};
typeof yoda; // -> "undefined"
funcName(); // -> "function"
So why do this right? as Yoda is 'undefined' when we checked the type, the bonus with a named function expression is the name is recognised within the function itself and can help dramatically when debugging as the name will show up in your call stack, whereas an anonymous function wouldn't show up in the stack.
const funcName = function yoda(param) {
console.log(typeof yoda === 'function'); // -> true
return typeof param;
}
funcName(3); // -> 'number'
funcName.name; // -> 'yoda'
So as you level-up it might be worth considering if Named Function Expressions are for you?
Arrow Functions
Ahh Arrow Functions, everyone's new favourite addition to ES6.
Arrow Functions are a Syntactic extension of Function Expressions, utilising what we call a fat arrow (or I prefer to call a rocket), and it can be constructed in a few different ways.
// -> no params
const funcName = () => {
// do something;
};
// -> one param
const funcName = param => {
// if one param the brackets arent needed;
};
// -> more than one param
const funcName = (paramOne, paramTwo, paramThree) => {
// but if more than one they are required;
};
// -> if the function is simple enough it can be simplified to a single line, removing the need for brackets after the rocket.
const funcName = (x, y) => x * y;
Like with all our functions so far there are some times when Arrow Functions, so let's go over a few of these gotchas.
It gets funky with This
Wes Bos can probably do a way better at explaining this, with this.
As he does such a good job I'll phone a friend and leave you to review that article rather than repeat.
Constructors
Arrows Functions can't be used as constructors, therefore 'New' cant be invoked with an Arrow Function.
Object literals
And the final sticky part ill cover is object literals, due to the syntax Arrow Functions can't decipher them, for example.
An ES5 object literal would operate like this.
const setColour = function (colour) {
return {value: colour}
};
let backgroundColour = setColour('Blue');
backgroundColour.value; // -> "Blue"
But since the Arrow Functions use the curly braces by default, they can't differentiate between a block scope and an object literal and would result in an error.
const setColour = colour => {value: colour };
But this can be overcome but wrapping them as such.
const setColour = colour => ({value: colour });
Immediately Invoked Function Expressions(IIFE)
As the name does suggest, this is a function that is invoked the moment it is defined.
(function () {
// do something;
})();
This one looks a bit weirder, but it is just an anonymous function wrapped in brackets and invoked immediately after.
They can be handy as they're invoked immediately, and not hoisted into the global scope (and this could be considered pollution), they cannot be expressed with a Rocket.
As they are invoked due to the compile process, they do not need a name, but they can be given one.
(function funcName() {
// do something;
})();
There are plenty of bonus features with IIFE but I will point you to an amazing article that covers all those quite clearly.
Well, I hope you liked the article if you reached this far a like or a share would be lovely if you were so inclined.
I will be back soon with some more JavaScript-related content.
Much luv
Coops
Top comments (3)
This works just fine for me, and I rather thought this was the point of hoisting.
My understanding is that with hoisting, the above example is re-arranged to the below form.
Which is why it does not produce an error.
Perhaps not, but var declarations are, so ...
is re-arranged to
Which does have the problem you described above, since var declarations are hoisted, but not the initializations, and we get something like "TypeError: funcName is not a function".
I'm not entirely sure you can reasonably call them a syntactic extension, since they have different semantics.
Well, your example won't result in an error, but it may be surprising when it always returns undefined.
value is a perfectly good label, and colour is a perfectly good expression, after all.
The moral of the story being that it's always a good idea to test your examples to see if they actually do what you expect. :)
Thanks for the feedback, Iโll review this tomorrow morning and edit
You're welcome. :)