Let's talk about JavaScript functions.
What's the primary purpose of a function? To break apart code into small, manageable, and reusable chunks. Functions are the fundamental building blocks of JavaScript and considered "first-class citizens".
Function Declaration
Functions are defined, or declared, with the function keyword.
// Function declaration
function captainsLog(starDate, destination) {
console.log(`Captain's Log: Star Date ${starDate}, Destination is ${destination}.`)
return 'Tea. Earl Grey. Hot.'
}
//Function invocation
captainsLog(73786.9, 'Risa')
// "Tea. Earl Grey. Hot."
// Captain's Log: Star Date 73786.9, Destination is Risa.
A side-note about return statements
Functions can have an optional return statement, however, a return statement is required if you want to actually return a value from the function.
Return statements should be the last statement within the function, as the return keyword stops execution of a function.
While return statements are optional, a function will ALWAYS have a return value. If the value is not specified with a return statement, then undefined
is returned.
Function Expression
Since functions are first-class citizens, they can be assigned to a variable.
let captainFullName = function(first, last) {
return `Captain ${first} ${last}`
}
captainFullName("Jean-Luc", "Picard")
// "Captain Jean-Luc Picard"
You'll notice a few differences between the function declaration and the function expression examples. Function expressions do not need function names as they are always invoked using the variable name.
One thing to keep in mind about function expressions is they are not hoisted. The function in this situation is the expression of the variable captainFullName
, which is not hoisted. The declaration of the variable captainFullName
is hoisted but not the function expression assigned to it. If this seems confusing, read more on hoisting here.
Immediately Invoked Function Expressions - IIFE (pronounced "iffy")
These are functions that are executed as soon as they are declared. While this type of function might not seem that useful, they do provide a sheltered place to create function scope for the contained variables.
(function(){
alert('The Prime Directive prohibits Starfleet personnel and spacecraft
from interfering in the normal development of any society, and mandates
that any Starfleet vessel or crew member is expendable to prevent
violation of this rule.')
})()
This format is essentially a function declaration nested within a function invocation:
(/* function */)()
As an IIFE is a type of closure, variables within the IIFE cannot be accessed outside the function.
Arrow Functions
This is mainly syntactic sugar for defining function expressions that are easier to understand and read. Let's rewrite the above function expression:
let captainFullName = (first, last) => {return `Captain ${first} ${last}`}
captainFullName("Jean-Luc", "Picard")
// "Captain Jean-Luc Picard"
While the primary use case for these are iterative functions that get applied over and over again to items in some sort of list, these can be used wherever appropriate. And, just as function expressions are not hoisted, neither are these.
One special thing to note, an arrow function does not have it's own this
. The this
value of the enclosing lexical scope is used instead. Arrow functions will follow the normal variable lookup rules, since this
isn't found in its current scope, it ends up finding the this
from its enclosing scope.
const captains = [
'James T Kirk',
'Jean-Luc Picard',
'Benjamin Sisko',
'Kathryn Janeway',
'Jonathan Archer'
]
console.log(captains.map(captain => `Captain ${captain}`))
// output: Array(5) [ "Captain James T Kirk", "Captain Jean-Luc Picard", "Captain Benjamin Sisko", "Captain Kathryn Janeway", "Captain Jonathan Archer" ]
Discussion (0)