How to Declare and Call a JavaScript Function

Learn how to declare and call functions in JavaScript. Covers function declarations, function expressions, hoisting behavior, naming rules, the difference between defining and invoking, and common patterns for organizing function code.

JavaScriptbeginner
10 min read

Declaring a function means creating it. Calling a function means running it. These two steps are separate in JavaScript: you define what a function does, then you execute it whenever you need that behavior. Understanding this separation is essential because JavaScript treats declarations and expressions differently when it comes to hoisting, scope, and how your code loads.

This tutorial covers every way to declare functions in JavaScript, how to call them correctly, hoisting behavior that affects when functions become available, and practical patterns for organizing your function code.

Function Declarations

A function declaration uses the function keyword followed by a name, parentheses for parameters, and curly braces for the body:

javascriptjavascript
function greet(name) {
  return `Hello, ${name}!`;
}
 
const message = greet("Alice");
console.log(message); // "Hello, Alice!"

Syntax Breakdown

javascriptjavascript
function functionName(param1, param2) {
  // function body
  return value;
}
ComponentRequiredDescription
function keywordYesStarts the declaration
Function nameYesUsed to call the function
Parameters ()Yes (even if empty)Inputs the function receives
Body {}YesCode that executes on each call
return statementNoSends a value back to the caller

Hoisting: Call Before Declaration

Function declarations are hoisted. JavaScript moves them to the top of their scope before running any code, so you can call them before the line where they appear:

javascriptjavascript
// This works because of hoisting
const result = add(3, 5);
console.log(result); // 8
 
function add(a, b) {
  return a + b;
}
javascriptjavascript
// Behind the scenes, JavaScript sees it as:
function add(a, b) {
  return a + b;
}
 
const result = add(3, 5);
console.log(result); // 8
Hoisting Only Applies to Declarations

Only function declarations are hoisted. Function expressions and arrow functions assigned to variables follow the hoisting rules of their variable keyword (let, const, var). A const function expression is not accessible before its definition line.

Function Expressions

A function expression creates a function and assigns it to a variable:

javascriptjavascript
const greet = function (name) {
  return `Hello, ${name}!`;
};
 
console.log(greet("Bob")); // "Hello, Bob!"

The function itself has no name (it is anonymous). The variable greet holds a reference to the function.

Named Function Expressions

You can give the function a name even in an expression. The name is only accessible inside the function body (useful for recursion and debugging):

javascriptjavascript
const factorial = function fact(n) {
  if (n <= 1) return 1;
  return n * fact(n - 1); // 'fact' is accessible here
};
 
console.log(factorial(5)); // 120
// console.log(fact(5));   // ReferenceError: fact is not defined

No Hoisting for Expressions

javascriptjavascript
// This throws an error
// console.log(multiply(3, 4)); // ReferenceError: Cannot access 'multiply' before initialization
 
const multiply = function (a, b) {
  return a * b;
};
 
console.log(multiply(3, 4)); // 12

How to Call a Function

Basic Call

Add parentheses after the function name to execute it:

javascriptjavascript
function sayHello() {
  console.log("Hello!");
}
 
sayHello(); // Hello!

Passing Arguments

Arguments go inside the parentheses, separated by commas:

javascriptjavascript
function formatPrice(amount, currency) {
  return `${currency}${amount.toFixed(2)}`;
}
 
console.log(formatPrice(29.9, "$"));  // "$29.90"
console.log(formatPrice(1499, "€")); // "€1499.00"

Storing the Return Value

javascriptjavascript
function getFullName(first, last) {
  return `${first} ${last}`;
}
 
// Store the result in a variable
const name = getFullName("John", "Doe");
console.log(name); // "John Doe"
 
// Use directly in another expression
console.log(getFullName("Jane", "Smith").toUpperCase()); // "JANE SMITH"
 
// Pass as argument to another function
console.log(getFullName("Bob", "Wilson").length); // 10

Calling Without Arguments

If a function expects parameters but you call it without arguments, the parameters become undefined:

javascriptjavascript
function greet(name) {
  return `Hello, ${name}!`;
}
 
console.log(greet());        // "Hello, undefined!"
console.log(greet("Alice")); // "Hello, Alice!"

Declaration vs Expression Comparison

FeatureDeclarationExpression
Syntaxfunction name() {}const name = function() {}
HoistedYes (fully hoisted)No (follows variable rules)
NamedAlwaysOptional
Semicolon afterNoYes (it is an assignment)
Use before definitionYesNo
OverwritableCan be redeclared in same scopeconst prevents reassignment
DebuggingName shown in stack tracesVariable name or "anonymous"

When to Use Each

javascriptjavascript
// Declaration: general-purpose functions
// Good when hoisting is useful or function is a primary building block
function calculateTax(price, rate) {
  return price * rate;
}
 
// Expression: callbacks, conditional functions, module patterns
// Good when you want to prevent hoisting or assign conditionally
const calculateDiscount = function (price, percent) {
  return price * (percent / 100);
};

Calling Functions Inside Functions

Functions can call other functions. This is how you build complex behavior from simple pieces:

javascriptjavascript
function isValidAge(age) {
  return typeof age === "number" && age >= 0 && age <= 150;
}
 
function isValidName(name) {
  return typeof name === "string" && name.trim().length > 0;
}
 
function validateUser(name, age) {
  const errors = [];
 
  if (!isValidName(name)) {
    errors.push("Name is required");
  }
 
  if (!isValidAge(age)) {
    errors.push("Age must be a number between 0 and 150");
  }
 
  return {
    valid: errors.length === 0,
    errors: errors,
  };
}
 
console.log(validateUser("Alice", 28));
// { valid: true, errors: [] }
 
console.log(validateUser("", -5));
// { valid: false, errors: ["Name is required", "Age must be a number between 0 and 150"] }

Functions with Multiple Return Points

Functions can have multiple return statements. Each acts as an exit point:

javascriptjavascript
function getLetterGrade(score) {
  if (score >= 90) return "A";
  if (score >= 80) return "B";
  if (score >= 70) return "C";
  if (score >= 60) return "D";
  return "F";
}
 
console.log(getLetterGrade(95)); // "A"
console.log(getLetterGrade(73)); // "C"
console.log(getLetterGrade(42)); // "F"

This pattern works well with if statements as guard clauses. Each condition checks and exits early, making the logic linear and easy to follow.

Immediately Invoked Function Expressions (IIFE)

You can define and call a function in one step by wrapping it in parentheses and adding ():

javascriptjavascript
(function () {
  const secret = "hidden";
  console.log("This runs immediately!");
  // secret is not accessible outside
})();
 
// Named IIFE
(function setup() {
  console.log("Initializing...");
})();

IIFEs create a private scope. Variables inside them do not leak into the global scope. This pattern was essential before ES6 modules, and it is still useful for one-time initialization scripts.

Practical Examples

Form Validator

javascriptjavascript
function validateEmail(email) {
  if (typeof email !== "string") return false;
  if (email.length === 0) return false;
  if (!email.includes("@")) return false;
  if (!email.includes(".")) return false;
  return true;
}
 
function validatePassword(password) {
  if (typeof password !== "string") return false;
  if (password.length < 8) return false;
  return true;
}
 
function validateForm(email, password) {
  const result = { valid: true, messages: [] };
 
  if (!validateEmail(email)) {
    result.valid = false;
    result.messages.push("Please enter a valid email");
  }
 
  if (!validatePassword(password)) {
    result.valid = false;
    result.messages.push("Password must be at least 8 characters");
  }
 
  return result;
}
 
console.log(validateForm("user@example.com", "secure123"));
// { valid: true, messages: [] }
 
console.log(validateForm("invalid", "short"));
// { valid: false, messages: ["Please enter a valid email", "Password must be at least 8 characters"] }

Temperature Converter

javascriptjavascript
function celsiusToFahrenheit(celsius) {
  return (celsius * 9) / 5 + 32;
}
 
function fahrenheitToCelsius(fahrenheit) {
  return ((fahrenheit - 32) * 5) / 9;
}
 
function formatTemperature(value, unit) {
  return `${value.toFixed(1)}°${unit}`;
}
 
const boiling = celsiusToFahrenheit(100);
console.log(formatTemperature(boiling, "F")); // "212.0°F"
 
const body = fahrenheitToCelsius(98.6);
console.log(formatTemperature(body, "C")); // "37.0°C"

Common Mistakes

Missing Parentheses

javascriptjavascript
function getTimestamp() {
  return Date.now();
}
 
// Bug: assigns the function itself, not its result
const time = getTimestamp;
console.log(time); // [Function: getTimestamp]
 
// Fix: call the function
const time = getTimestamp();
console.log(time); // 1709510400000

Declaring Inside a Loop Unnecessarily

javascriptjavascript
// Wasteful: creates a new function on every iteration
for (let i = 0; i < 100; i++) {
  function process(val) {
    return val * 2;
  }
  console.log(process(i));
}
 
// Better: declare once, call many times
function process(val) {
  return val * 2;
}
 
for (let i = 0; i < 100; i++) {
  console.log(process(i));
}
One Function, One Job

If a function does more than one distinct thing (validates data AND sends an email AND updates the database), split it into separate functions. Single-responsibility functions are easier to test, debug, and reuse.

Rune AI

Rune AI

Key Insights

  • Declarations use function name() and are fully hoisted: callable before their definition line
  • Expressions use const name = function() and are not hoisted: must be defined before use
  • Call with parentheses, reference without: greet() runs the function, greet passes it as a value
  • Multiple return points work as guard clauses: check conditions early and exit, keeping logic flat
  • Each function should do one thing: single-responsibility functions are easier to test and reuse
RunePowered by Rune AI

Frequently Asked Questions

Should I use function declarations or expressions?

Use declarations for top-level utility functions that you want available throughout the file. Use expressions when assigning functions to variables, passing them as callbacks, or when you want to prevent hoisting. Many modern codebases default to `const` expressions for consistency, but declarations are perfectly valid and easier for beginners.

Can I redeclare a function with the same name?

With function declarations, yes. The second declaration silently overwrites the first. With `const` expressions, no. Attempting to redeclare a `const` variable throws a SyntaxError. This is one advantage of expressions: `const` prevents accidental overwriting.

What does "calling" vs "referencing" a function mean?

Calling means executing the function by adding parentheses: `greet()`. Referencing means using the function's name without parentheses: `greet`. A reference gives you the function object itself, not its result. You reference functions when passing them as callbacks or assigning them to variables.

How many functions should a file have?

There is no fixed limit. A small utility file might have 2 to 3 functions. A complex module might have 20 or more. The important thing is that each function has a clear purpose and the file has a coherent theme. If a file grows beyond 300 to 400 lines, consider splitting it into focused modules.

Is there a performance difference between declarations and expressions?

No meaningful difference. Both create function objects in memory. The only behavioral difference is hoisting. Modern [JavaScript engine](/tutorials/programming-languages/javascript/what-is-a-javascript-engine-a-complete-guide)s optimize both forms identically. Choose based on code organization preferences, not performance.

Conclusion

Declaring a function stores a reusable block of code. Calling a function executes it. Function declarations are hoisted (available before their definition line), while function expressions follow variable scoping rules and are not hoisted. Both create the same kind of function object under the hood. Use declarations for top-level building blocks and expressions for callbacks, conditional assignments, and cases where you want const to prevent reassignment. Structure your code so each function does one thing well, name it clearly, and compose small functions into larger operations.