In JavaScript, parameters receive values in a function definition, while arguments are the expressions passed when the function is called.
Parameter vs. Argument: The Short Answer
Look at the function definition and its invocation side by side:
function greet(name, punctuation) {
return `Hello, ${name}${punctuation}`;
}
console.log(greet("Mina", "!"));
Hello, Mina!
In the definition, name and punctuation are parameters:
function greet(name, punctuation) {
// ^^^^ ^^^^^^^^^^^ parameters
}
In the call, "Mina" and "!" are argument expressions:
greet("Mina", "!");
// ^^^^^^ ^^^ arguments
The string expressions are evaluated at the call site. Their resulting values initialize the parameters by position. "Mina" initializes name, and "!" initializes punctuation.
A useful mnemonic is:
- Parameters receive.
- Arguments are passed.
Parameters belong to the reusable function definition. Arguments belong to a particular call. The same parameters can therefore receive different values on every invocation:
function greet(name, punctuation) {
return `Hello, ${name}${punctuation}`;
}
console.log(greet("Mina", "!"));
console.log(greet("Ravi", "?"));
Hello, Mina!
Hello, Ravi?
Developers sometimes use the two terms interchangeably in casual conversation. The distinction becomes useful when diagnosing a call, explaining an unexpected value, or answering a question about the number of arguments a function receives.
How Arguments Become Parameter Values
An argument does not have to be a literal such as "Mina" or 42. It can be any expression used at the call site, including:
- A literal
- A variable
- A computed expression
- An object
- A callback function
This example supplies all five forms:
const team = "UI";
function describe(label, count, options, formatter, active) {
const text = `${label}:${count}:${options.mode}:${active}`;
return formatter(text);
}
const result = describe(
"cards",
team.length,
{ mode: "compact" },
text => text.toUpperCase(),
true
);
console.log(result);
CARDS:2:COMPACT:TRUE
The function has five parameters: label, count, options, formatter, and active. The call supplies five argument expressions.
JavaScript evaluates the argument expressions from left to right. Only after that evaluation finishes does it initialize the parameters from left to right, so a later default can use an earlier parameter:
function trace(a, b = a) {
console.log("parameters", a, b);
}
trace(
(console.log("argument 1"), 7),
(console.log("argument 2"), undefined)
);
argument 1
argument 2
parameters 7 7
In the five-argument call above, the resulting values initialize the parameters by position:
| Position | Argument expression | Resulting value | Parameter |
|---|---|---|---|
| First | "cards" | "cards" | label |
| Second | team.length | 2 | count |
| Third | { mode: "compact" } | The new object | options |
| Fourth | text => text.toUpperCase() | The callback function | formatter |
| Fifth | true | true | active |
Parameter names do not participate in this matching. The first argument initializes the first parameter, the second argument initializes the second parameter, and so on.
Each new call repeats this process. The function keeps the same parameter declarations, but those parameters receive values from the current call:
function subtract(left, right) {
return left - right;
}
console.log(subtract(10, 3));
console.log(subtract(30, 8));
7
22
left and right are reused as parameter names. The calls provide different arguments, so the parameter values differ during each invocation.
This same distinction appears when a function is invoked with Function.prototype.call or Function.prototype.apply. The invocation syntax changes, but the supplied values still initialize the declared parameters.
What Happens When the Counts Do Not Match?
JavaScript allows the number of supplied arguments to differ from the number of declared parameters. An ordinary non-rest parameter without a corresponding argument becomes undefined unless the declaration provides a default. A rest parameter always receives an Array, which may be empty. Extra arguments do not cause a JavaScript runtime error merely because no declared parameter matches them.
Consider a function with two ordinary parameters:
function showPair(first, second) {
console.log(String(first));
console.log(String(second));
}
showPair();
undefined
undefined
The call supplies zero arguments. Both parameters receive undefined.
Supplying one argument initializes the first parameter only:
function showPair(first, second) {
console.log(String(first));
console.log(String(second));
}
showPair("A");
A
undefined
An explicit undefined has the same effect on that parameter value:
function showPair(first, second) {
console.log(String(first));
console.log(String(second));
}
showPair("A", undefined);
A
undefined
Default parameters replace omitted or undefined values
A default parameter supplies another value when the corresponding argument is omitted or evaluates to undefined:
function createLabel(text = "Untitled") {
console.log(String(text));
}
createLabel();
createLabel(undefined);
createLabel("Profile");
Untitled
Untitled
Profile
The default expression runs when the function is called. This matters when the expression computes a fresh value for each invocation.
null, 0, false, and an empty string do not activate a default:
function inspect(value = "default") {
console.log(JSON.stringify(value));
}
inspect(null);
inspect(0);
inspect(false);
inspect("");
null
0
false
""
A common mistake is to describe a default as a replacement for every falsy value. It is narrower than that. Only an omitted argument or an undefined value activates the parameter default.
Destructuring can have defaults at two levels:
function readSettings({ theme = "light" } = {}) {
console.log(theme);
}
readSettings();
readSettings({});
readSettings({ theme: undefined });
readSettings({ theme: null });
try {
readSettings(null);
} catch (error) {
console.log(error.name);
}
light
light
light
null
TypeError
The outer = {} handles an omitted or undefined object argument. It does not replace null, so destructuring a null argument throws a TypeError. The inner theme = "light" handles a missing or undefined property, while passing null as the property value preserves null. Arguments such as false, 0, and "" can be boxed for property access, so they do not throw here; their missing theme property activates the inner default.
Extra arguments remain part of the call
This call supplies three arguments to a function with one declared parameter:
function firstOnly(first) {
console.log(first);
console.log(arguments.length);
}
firstOnly("A", "B", "C");
A
3
first receives "A". The remaining arguments do not acquire named parameter bindings, but they still belong to the call. A rest parameter can collect them, and a non-arrow function can inspect all supplied arguments through arguments.
TypeScript can reject calls that JavaScript runs
JavaScript runtime behavior and TypeScript checking answer different questions. JavaScript permits missing and extra arguments in a call. TypeScript checks whether the call matches the function's declared parameter types and allowed argument count.
function total(price: number, quantity: number) {
return price * quantity;
}
total(10);
total(10, 2, 5);
TypeScript reports both calls during checking because their argument counts do not match this declaration. The corresponding JavaScript runtime would still attempt both calls.
Optional parameters and trailing defaulted TypeScript parameters permit omission:
function label(name: string, suffix = "!") {
return `${name}${suffix}`;
}
label("Mina");
label("Mina", "?");
A defaulted parameter before a required parameter still occupies a required argument position. Pass undefined to activate its default:
function position(x = 1, y: number) {
return x + y;
}
position(undefined, 2);
A separate callback trap concerns optional parameters. In a callback type, index?: number means the callback's caller is allowed to omit the second argument:
type Visitor = (item: string, index?: number) => void;
function run(visitor: Visitor) {
visitor("A");
}
const showIndex: Visitor = (item, index) => {
console.log(index.toFixed(0));
// ^^^^^ 'index' is possibly 'undefined'
};
If the caller always supplies an index, make it required in the callback type. Implementations may still declare fewer parameters when they do not use it:
type IndexedVisitor = (item: string, index: number) => void;
function runIndexed(visitor: IndexedVisitor) {
visitor("A", 0);
}
runIndexed(item => console.log(item));
Rest Parameters, Spread Arguments, and arguments
The ... token can appear in both a function declaration and a function call. Its role depends on its location.
A rest parameter appears in the declaration:
function collect(first, ...remaining) {
console.log(first);
console.log(JSON.stringify(remaining));
}
collect("alpha", "beta", "gamma");
alpha
["beta","gamma"]
first receives the first argument. remaining is a real Array containing the rest.
A function can declare only one rest parameter. It must be the last parameter, and it cannot have a default value or a trailing comma.
Spread syntax appears at the call site:
function collect(first, ...remaining) {
console.log(first);
console.log(JSON.stringify(remaining));
}
const values = ["beta", "gamma"];
collect("alpha", ...values);
alpha
["beta","gamma"]
Here, ...values supplies the iterable's values as separate arguments. It does not create a rest parameter. The declaration's ...remaining collects arguments, while the call's ...values supplies them.
| Feature | Location | What it does | Result |
|---|---|---|---|
| Rest parameter | Function declaration | Collects remaining arguments | A real Array |
| Spread arguments | Function call | Supplies iterable values as separate arguments | Separate argument values |
arguments | Inside a non-arrow function | Exposes all supplied arguments | An array-like object |
The arguments object includes every argument passed, including arguments that have no matching named parameter:
function received(first) {
console.log(arguments.length);
console.log(JSON.stringify(Array.from(arguments)));
}
received("A", "B", "C");
3
["A","B","C"]
arguments.length is the number of arguments actually supplied. It is different from the function's length property, which describes expected formal parameters according to specific counting rules.
Arrow functions do not create their own arguments binding. If an arrow refers to arguments, it can resolve to a surrounding non-arrow function's binding:
function outer() {
return () => arguments.length;
}
const countOuterArguments = outer("A", "B");
console.log(countOuterArguments());
2
The arrow was later called with zero arguments. The printed 2 comes from outer's arguments, not from an arguments object owned by the arrow.
Prefer a rest parameter when the function deliberately accepts a variable number of values. Rest names the relevant values and gives an Array directly. The older arguments object remains useful when reading existing non-arrow functions or when examining every supplied argument.
Frontend Examples That Expose the Difference
Frontend code passes functions around constantly. Precise terminology helps separate the callback's declaration from each invocation.
Array callbacks declare parameters
In this map callback, price and index are parameters:
const prices = [10, 20];
const labels = prices.map(function format(price, index) {
return `${index}:${price}`;
});
console.log(labels.join("|"));
0:10|1:20
During each callback invocation, the current element and index arrive as arguments. The first call initializes price with 10 and index with 0. The second initializes them with 20 and 1.
The callback could ignore index by omitting that parameter from its declaration. That does not require changing the arguments supplied by the caller.
Event handlers receive an event argument
In this browser example, event is a parameter of handleClick:
const button = document.querySelector("button");
button.addEventListener("click", function handleClick(event) {
console.log(event.type);
});
When the handler is invoked for a click, the event object is the argument whose value initializes event. Renaming the parameter to clickEvent changes the local name, not the supplied argument.
Higher-order functions have separate calls
A higher-order function accepts or returns another function. Each function has its own parameter list, and each invocation has its own arguments:
function withPrefix(prefix) {
return function format(value) {
return `${prefix}:${value}`;
};
}
const warning = withPrefix("warn");
console.log(warning("missing"));
warn:missing
The call withPrefix("warn") passes "warn" as an argument for prefix. The later call warning("missing") passes "missing" as an argument for value. This distinction is useful when practicing partial application and currying.
Destructuring still describes one parameter position
A destructuring pattern can unpack one object argument:
function renderCard({ title, featured = false }) {
return `${title}:${featured}`;
}
console.log(renderCard({ title: "Closures", featured: true }));
Closures:true
The call supplies one object argument. The declaration has one parameter position containing an object destructuring pattern. title and featured are bindings created from properties of that object. They are not two separately supplied arguments.
React function components follow the same model:
function ProfileCard({ name, role = "Engineer" }) {
return (
<article>
<h2>{name}</h2>
<p>{role}</p>
</article>
);
}
<ProfileCard name="Mina" role="Designer" />
ProfileCard receives one props object. Destructuring name and role in its parameter list does not turn those properties into separate arguments.
Interview Checks and Common Mistakes
Try to predict each result before reading the explanation.
Do omitted and undefined arguments use the default?
function valueOf(input = 7) {
return input;
}
console.log(valueOf());
console.log(valueOf(undefined));
console.log(valueOf(null));
console.log(valueOf(false));
7
7
null
false
The omitted argument and explicit undefined activate the default. null and false remain the parameter values supplied by their calls.
Do extra arguments change the named parameters?
function join(left, right) {
console.log(`${left}:${right}`);
console.log(arguments.length);
}
join("A", "B", "C");
A:B
3
The first two arguments initialize left and right. The third has no matching named parameter, but arguments.length still counts it.
Is ...items rest or spread?
function list(...items) {
return items.join(",");
}
const names = ["Mina", "Ravi"];
console.log(list(...names));
Mina,Ravi
...items is a rest parameter because it appears in the declaration. ...names is spread syntax because it appears in the call.
What does Function.length count?
function inspect(first, second = 2, { third } = {}, ...rest) {}
console.log(inspect.length);
1
For the Function Length property, only parameters before the first default parameter are counted. A destructuring pattern counts as one parameter when it is counted, and a rest parameter is excluded.
Does an arrow function own arguments?
No. An arrow function does not create its own arguments binding. Use a rest parameter when the arrow needs the values supplied to its call:
const count = (...values) => values.length;
console.log(count("A", "B", "C"));
3
A concise interview answer is: "Parameters are binding identifiers or binding patterns declared in a function's parameter list. Arguments are expressions at a call site, and their resulting values initialize parameters by position. Ordinary non-rest parameters without corresponding arguments become undefined unless defaults apply; a rest parameter always receives an Array, which may be empty. Extra JavaScript arguments are allowed and can be collected with rest parameters."
For more timed practice with these call-site traps, UIReady Premium Annual includes a longer study path built around writing answers and running tests.