Skip to content

Function Definitions

JavaScript functions are fundamental building blocks. They are defined primarily using the function keyword or the newer arrow function syntax.

You can define functions using function declarations, function expressions, and arrow functions.

A function declaration defines a named function. The syntax is:

function functionName(parameter1, parameter2) {
// code to be executed
return result; // optional
}

Declared functions are not executed immediately. They are “hoisted” (see below) and available throughout their scope, ready to be called (invoked) later.

// Declaring a function
function multiply(a, b) {
return a * b;
}
// Calling the function
const product = multiply(5, 10); // product is 50
Note on Semicolons: Function declarations are statements, but unlike most statements, they are not typically ended with a semicolon. However, JavaScript’s Automatic Semicolon Insertion (ASI) usually handles this well.

A JavaScript function can also be defined using an expression. A function expression can be stored in a variable.

It’s a best practice to use const for function expressions to prevent accidental reassignment.

// Storing a function expression in a variable
const calculateSum = function(a, b) {
return a + b;
}; // Semicolon here because it's part of an assignment statement.
// Calling the function using the variable
const sum = calculateSum(4, 3); // sum is 7

The function in the example above is an anonymous function (a function without a name) assigned to the calculateSum variable. Functions stored in variables are invoked using the variable name.

Arrow functions, introduced in ES6, provide a more concise syntax for writing function expressions. They are always anonymous.

// Arrow function with multiple parameters and a block body
const greet = (name) => {
return `Hello, ${name}!`;
};
// Arrow function with one parameter (parentheses optional)
const square = x => x * x;
// Arrow function with no parameters
const getRandom = () => Math.random();
console.log(greet('World')); // Output: Hello, World!
console.log(square(5)); // Output: 25

Key characteristics of arrow functions:

  • Concise syntax, especially for simple functions.
  • They do not have their own this binding. The this value is inherited from the enclosing lexical scope. This is often a desired behavior, especially in callbacks.
  • They cannot be used as constructor functions (i.e., with new).
  • They do not have an arguments object. Use rest parameters (...args) instead.

For more details on this in arrow functions, consult resources on JavaScript scope and context.

JavaScript functions can technically be defined with the built-in Function constructor. However, this method is generally not recommended.

// Example (discouraged)
const multiplyConstructor = new Function("a", "b", "return a * b");
const result = multiplyConstructor(4, 3); // result is 12

Reasons to avoid new Function():

  • Security risks: It evaluates code from strings, similar to eval().
  • Performance issues: Functions created this way are harder for the JavaScript engine to optimize.
  • Readability: Code is less clear and harder to debug.

Stick to function declarations, function expressions, or arrow functions.

Hoisting is JavaScript’s behavior of notionally moving declarations to the top of their scope before code execution.

Function Declarations: Are fully hoisted. This means you can call a function declaration before it appears in the code.

sayHello(); // Works because greet is hoisted
function sayHello() {
console.log("Hello!");
}

Function Expressions and Arrow Functions: Are not hoisted in the same way. If defined with var, the variable declaration (var x;) is hoisted, but the assignment (x = function() {...};) is not. If defined with let or const, the variable is hoisted but remains in a ‘temporal dead zone’ until the declaration is encountered, so you cannot access it before.

// tryToCall(); // This would cause an error (ReferenceError or TypeError depending on var/let/const)
const tryToCall = function() {
console.log("Called!");
};
// Or using an arrow function:
// const tryToCallArrow = () => console.log("Arrow called!");

Understanding hoisting is crucial for avoiding unexpected errors. Using let and const generally leads to more predictable behavior.

Immediately Invoked Function Expressions (IIFE)

Section titled “Immediately Invoked Function Expressions (IIFE)”

A function expression can be made to execute immediately after it’s defined. This pattern is known as an IIFE (Immediately Invoked Function Expression), formerly often called a self-invoking function.

An IIFE is invoked automatically because the expression is followed by (). To make it clear that it’s an expression, the function is wrapped in parentheses.

(function() {
const message = "Hello from IIFE!";
console.log(message); // This will execute immediately
})();
// IIFE with arrow function
(() => {
const secret = "This is private to the IIFE.";
console.log(secret);
})();

IIFEs are useful for creating a local scope to avoid polluting the global namespace and for one-time setup code.

In JavaScript, functions are first-class citizens. This means they can be treated like any other value: assigned to variables, passed as arguments to other functions, and returned from functions.

function add(a, b) {
return a * b;
}
const operation = add; // Assigning function to a variable
const result1 = operation(4, 3); // result1 is 12
const result2 = add(4, 3) * 2; // Using function return value in an expression
// result2 is 24

This flexibility is a core part of JavaScript’s power, enabling patterns like callbacks and higher-order functions.

While the typeof operator returns "function" for functions, they are fundamentally a special type of object in JavaScript.

Like objects, functions can have properties and methods.

The arguments.length property (available in non-arrow functions) returns the number of arguments actually passed to the function when it was invoked:

function countArgs(a, b) {
console.log(arguments.length); // Number of arguments passed
// Modern approach: use rest parameters
// function countArgsModern(...args) { console.log(args.length); }
}
countArgs(1, 2, 3); // Output: 3

Note: The arguments object is an array-like object. For modern JavaScript, it’s often better to use rest parameters (...args) which provide a true array.

The toString() method returns the function’s source code as a string:

function exampleMultiply(a, b) {
return a * b;
}
const funcAsString = exampleMultiply.toString();
console.log(funcAsString);
/* Output might be:
"function exampleMultiply(a, b) {
return a * b;
}"
*/
Key Terms: A function defined as a property of an object is called a method. A function designed to create new objects (using new) is called a constructor function (arrow functions cannot be constructors).