Q1If you declare function double(n) { n * 2; } and run console.log(double(4));, what gets displayed?
Function Declarations and Function Expressions — Arguments and return
Learn function declarations, arguments and return, function expressions, and why a missing return gives you undefined.
If you write the tax-included price formula directly in three places — the product list, the cart, and the order confirmation — then a tax rate change means fixing all three, and any screen you miss keeps showing the old amount.
This article covers function declarations, which give a piece of logic a name you can call, function expressions, which store a function in a variable as a value, and the value that return sends back.
Naming Logic So You Can Call It — function Declarations and Parameters
The logic for a product's tax-included price is the same every time; only the unit price changes. Since the price you pass in is the only difference, you can give the calculation itself a name, and then the list and the cart simply call it by that name.
A function (a named block of code that you can call as many times as you like) is declared in the form function name(parameters) { body }. The parameters in the parentheses are variables that receive a value on each call, and the value you write after return (the return value) goes back to the caller.
// Give the tax-included price logic the name taxIncluded
function taxIncluded(price) {
const tax = Math.floor(price * 0.1);
return price + tax; // Send the calculated value back to the caller
}
// Call the same function with different unit prices
console.log(taxIncluded(1200)); // 1320
console.log(taxIncluded(980)); // 1078
// If you forget to pass a value, price is left undefined
console.log(taxIncluded()); // NaN
price changes, so does the value that comes back. A call that passes no value leaves price as undefined, and the result is NaN.price receives only the value, so whether you write 1200 directly or pass a variable like itemPrice, the function works exactly the same way.
Taking Multiple Arguments — Matched by Position
When the discount rate varies by membership tier or sale, a function that takes only the unit price isn't enough. If the caller can pass the discount rate too, the calculation stays in one place and only the rate is decided at the call site.
Separate parameters with commas. The values at the call site are matched in the order you write them: the first value goes into the first parameter, the second into the second. They aren't matched by name, so passing them in the wrong order is still valid code, and nothing warns you.
// Take a unit price and a discount rate, and return the discounted price
function applyDiscount(price, rate) {
return Math.floor(price * (1 - rate));
}
// The first value goes into price, the second into rate
console.log(applyDiscount(2400, 0.2)); // 1920
console.log(applyDiscount(2400, 0.05)); // 2280
// Even with the order swapped, the calculation still runs
console.log(applyDiscount(0.2, 2400)); // -480
applyDiscount, with only their order changed. Swapping them doesn't cause an error — only the result changes.A call shows only the values, so reading applyDiscount(0.2, 2400) won't reveal the mix-up. When you get an impossible value like -480, check the order of the values in the call against the function's definition.
Treating Functions as Values — Function Expressions and Variables
Standard and express shipping use entirely different formulas. Instead of spelling out which one to use at every call site, you can store the function itself in a variable, and the caller just calls that variable.
A function expression (a way of assigning a function to a variable as a value) is an assignment statement written as const name = function (parameters) { body };. A function declaration is ready before the code starts running from top to bottom, whereas a function expression's variable only receives the function when the assignment line runs (the mechanism is covered in the article on scope and hoisting).
// A function declaration can be called even from lines above it
console.log(expressShipping(1.5)); // 900
function expressShipping(weight) {
return weight <= 2 ? 900 : 1300;
}
// Function expression: assign a function to a variable as a value
const normalShipping = function (weight) {
return weight <= 2 ? 500 : 800;
};
// Without parentheses, the function itself goes into another variable
const feeRule = normalShipping;
console.log(feeRule(3)); // 800
console.log(typeof feeRule); // function
console.log(typeof normalShipping(3)); // number
ReferenceError. A function stored by a function expression can't be called until the assignment line runs.The full error message is ReferenceError: Cannot access 'normalShipping' before initialization. Also note the feeRule line in the code above: assigning a function name without parentheses puts the function itself into another variable.
Declare the Same Name Twice and the Later One Wins
Because function declarations are set up before the code runs, if you declare two with the same name, even a call on the line right after the first one runs the later body. Nothing stops execution, so a duplicate name far away in the file is easy to miss. With a const function expression, the second declaration is a SyntaxError, and the code never starts running.
What Happens Without a Return Value — Forgetting return
If a function uses console.log, text appears on screen when you call it. Since something shows up, it looks like it works, but if you store its return value in a variable and use it, the string you expected isn't there.
return sends a value back and ends the function right there. A function without return returns undefined — displaying something and returning a value are two separate actions. console.log only prints to the screen; it hands nothing back to the caller.
// With return: the text goes back to the caller
function formatLabel(name, stock) {
return `${name} (${stock} left)`;
console.log("Unreachable"); // Comes after return, so it never runs
}
// Without return: it prints, but the return value is undefined
function printLabel(name, stock) {
console.log(`${name} (${stock} left)`);
}
const label = formatLabel("Desk Lamp", 3);
console.log(label); // Desk Lamp (3 left)
const printed = printLabel("USB Hub", 5); // USB Hub (5 left)
console.log(printed); // undefined
| How the function is written | What happens when called | What the caller gets |
|---|---|---|
| Returns the text with return | The text goes back to the caller | Desk Lamp (3 left) |
| Has only console.log | Prints to the screen but returns nothing | undefined |
| console.log after return | Lines after return don't run | The text still comes back |
When the caller is going to use the value, hand it back with return instead of displaying it.
A Line Break After return Means No Value Comes Back
If you break the line right after return and put the value on the next line, JavaScript treats the statement as ending on the return line, and the function returns undefined. It's an easy mistake to make when you move a long template literal to its own line for readability. Always start the value on the same line as return.
Knowledge Check
Answer each question one by one.
Q2If you call function fee(price, rate) { return price * rate; } as fee(0.2, 1000), what goes into price?
Q3What happens if you call calc(1) on a line before the assignment const calc = function (n) { return n + 1; };?