50% offEnding soon

Parameter vs. Argument in JavaScript

18 min read

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:

Two distinct phases1 Evaluate expressionsargument 1 → 7argument 2 →undefined2 Initialize parametersa = 7b = a = 7The default reads a after a has received 7.Console order: argument 1 → argument 2 → parameters
Argument expressions are evaluated before parameter defaults are resolved.
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:

PositionArgument expressionResulting valueParameter
First"cards""cards"label
Secondteam.length2count
Third{ mode: "compact" }The new objectoptions
Fourthtext => text.toUpperCase()The callback functionformatter
Fifthtruetrueactive

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.

Argument count can differfirstsecondno argumentsundefinedundefinedtwo arguments“A”“B”three arguments“A”“B”“C” remains in the call
JavaScript aligns arguments to parameters without requiring equal counts.

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.

Will the default run?Argument omittedor undefined?YESUse the defaultvalueNOKeep null, false,0, or empty stringFalsy does not mean missing.
Defaults have a narrow trigger: omitted or undefined, not every falsy value.

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.

Two default boundariesOuter default: argument = {}omitted orundefineduse {}Inner default: theme = “light”missing property→ “light”theme: null→ nullargument null → TypeError before the inner gate
Destructuring defaults guard the argument and its property separately.

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.

FeatureLocationWhat it doesResult
Rest parameterFunction declarationCollects remaining argumentsA real Array
Spread argumentsFunction callSupplies iterable values as separate argumentsSeparate argument values
argumentsInside a non-arrow functionExposes all supplied argumentsAn 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.

Two functions, two callswithPrefix(“warn”)prefix = “warn”returned format(value)remembers prefixwarning(“missing”)value = “missing”“warn:missing”
Each function call has its own argument-to-parameter mapping.

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.

One argument, multiple bindingsone objectargumenttitle: “Closures”featured: trueone parameter slot{ title, featured }binding: titlebinding: featuredThe split happens inside the function.
Object destructuring creates multiple bindings from one argument position.

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.

What inspect.length countsfirstCOUNTEDsecond = 2STOP{ third }not counted...restexcluded1inspect.length = 1Visible after the stop does not mean counted.
Function.length stops counting when it reaches the first default parameter.

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.

Frequently asked questions

What is the difference between a parameter and an argument in JavaScript?
A parameter is a binding identifier or binding pattern declared in a function's parameter list. An argument is an expression supplied when that function is called, and its resulting value initializes the corresponding parameter.
What happens when a JavaScript argument is missing?
An ordinary non-rest parameter without a corresponding argument receives undefined, and a default replaces that value when the argument is omitted or explicitly undefined. A rest parameter always receives an Array, which is empty when no arguments remain.
Do null and false activate a default parameter?
No. A default parameter applies only when the argument is omitted or evaluates to undefined. Values such as null, false, 0, and an empty string remain unchanged.
Are rest parameters and spread arguments the same?
No. A rest parameter appears in a function definition and collects remaining arguments into an Array. Spread syntax appears at the call site and supplies values from an iterable as separate arguments.
Does a destructured React props parameter create several arguments?
No. A React function component receives one props object. Destructuring that object in the parameter list creates property bindings, but the component still receives one argument.