Functions
BaselineWidely available *
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
* Some parts of this feature may have varying levels of support.
Generally speaking, a function is a "subprogram" that can becalled by code external (or internal, in the case of recursion) to the function. Like the program itself, a function is composed of a sequence of statements called thefunction body. Values can bepassed to a function as parameters, and the function willreturn a value.
In JavaScript, functions arefirst-class objects, because they can be passed to other functions, returned from functions, and assigned to variables and properties. They can also have properties and methods just like any other object. What distinguishes them from other objects is that functions can be called.
For more examples and explanations, see theJavaScript guide about functions.
Description
Function values are typically instances ofFunction
. SeeFunction
for information on properties and methods ofFunction
objects. Callable values causetypeof
to return"function"
instead of"object"
.
Note:Not all callable values areinstanceof Function
. For example, theFunction.prototype
object is callable but not an instance ofFunction
. You can also manually set theprototype chain of your function so it no longer inherits fromFunction.prototype
. However, such cases are extremely rare.
Return value
By default, if a function's execution doesn't end at areturn
statement, or if thereturn
keyword doesn't have an expression after it, then the return value isundefined
. Thereturn
statement allows you to return an arbitrary value from the function. One function call can only return one value, but you can simulate the effect of returning multiple values by returning an object or array anddestructuring the result.
Note:Constructors called withnew
have a different set of logic to determine their return values.
Passing arguments
Parameters and arguments have slightly different meanings, but in MDN web docs, we often use them interchangeably. For a quick reference:
function formatNumber(num) { return num.toFixed(2);}formatNumber(2);
In this example, thenum
variable is called the function'sparameter: it's declared in the parenthesis-enclosed list of the function's definition. The function expects thenum
parameter to be a number — although this is not enforceable in JavaScript without writing runtime validation code. In theformatNumber(2)
call, the number2
is the function'sargument: it's the value that is actually passed to the function in the function call. The argument value can be accessed inside the function body through the corresponding parameter name or thearguments
object.
Arguments are alwayspassed by value and neverpassed by reference. This means that if a function reassigns a parameter, the value won't change outside the function. More precisely, object arguments arepassed by sharing, which means if the object's properties are mutated, the change will impact the outside of the function. For example:
function updateBrand(obj) { // Mutating the object is visible outside the function obj.brand = "Toyota"; // Try to reassign the parameter, but this won't affect // the variable's value outside the function obj = null;}const car = { brand: "Honda", model: "Accord", year: 1998,};console.log(car.brand); // Honda// Pass object reference to the functionupdateBrand(car);// updateBrand mutates carconsole.log(car.brand); // Toyota
Thethis
keyword refers to the object that the function is accessed on — it does not refer to the currently executing function, so you must refer to the function value by name, even within the function body.
Defining functions
Broadly speaking, JavaScript has four kinds of functions:
- Regular function: can return anything; always runs to completion after invocation
- Generator function: returns a
Generator
object; can be paused and resumed with theyield
operator - Async function: returns a
Promise
; can be paused and resumed with theawait
operator - Async generator function: returns an
AsyncGenerator
object; both theawait
andyield
operators can be used
For every kind of function, there are multiple ways to define it:
- Declaration
- Expression
- Constructor
Function()
,GeneratorFunction()
,AsyncFunction()
,AsyncGeneratorFunction()
In addition, there are special syntaxes for definingarrow functions andmethods, which provide more precise semantics for their usage.Classes are conceptually not functions (because they throw an error when called withoutnew
), but they also inherit fromFunction.prototype
and havetypeof MyClass === "function"
.
// Constructorconst multiply = new Function("x", "y", "return x * y");// Declarationfunction multiply(x, y) { return x * y;} // No need for semicolon here// Expression; the function is anonymous but assigned to a variableconst multiply = function (x, y) { return x * y;};// Expression; the function has its own nameconst multiply = function funcName(x, y) { return x * y;};// Arrow functionconst multiply = (x, y) => x * y;// Methodconst obj = { multiply(x, y) { return x * y; },};
All syntaxes do approximately the same thing, but there are some subtle behavior differences.
- The
Function()
constructor,function
expression, andfunction
declaration syntaxes create full-fledged function objects, which can be constructed withnew
. However, arrow functions and methods cannot be constructed. Async functions, generator functions, and async generator functions are not constructible regardless of syntax. - The
function
declaration creates functions that arehoisted. Other syntaxes do not hoist the function and the function value is only visible after the definition. - The arrow function and
Function()
constructor always createanonymous functions, which means they can't easily call themselves recursively. One way to call an arrow function recursively is by assigning it to a variable. - The arrow function syntax does not have access to
arguments
orthis
. - The
Function()
constructor cannot access any local variables — it only has access to the global scope. - The
Function()
constructor causes runtime compilation and is often slower than other syntaxes.
Forfunction
expressions, there is a distinction between the function name and the variable the function is assigned to. The function name cannot be changed, while the variable the function is assigned to can be reassigned. The function name can be different from the variable the function is assigned to — they have no relation to each other. The function name can be used only within the function's body. Attempting to use it outside the function's body results in an error (or gets another value, if the same name is declared elsewhere). For example:
const y = function x() {};console.log(x); // ReferenceError: x is not defined
On the other hand, the variable the function is assigned to is limited only by its scope, which is guaranteed to include the scope in which the function is declared.
A function declaration also creates a variable with the same name as the function name. Thus, unlike those defined by function expressions, functions defined by function declarations can be accessed by their name in the scope they were defined in, as well as in their own body.
A function defined bynew Function
will dynamically have its source assembled, which is observable when you serialize it. For example,console.log(new Function().toString())
gives:
function anonymous() {}
This is the actual source used to compile the function. However, although theFunction()
constructor will create the function with nameanonymous
, this name is not added to the scope of the body. The body only ever has access to global variables. For example, the following would result in an error:
new Function("alert(anonymous);")();
A function defined by a function expression or by a function declaration inherits the current scope. That is, the function forms a closure. On the other hand, a function defined by aFunction
constructor does not inherit any scope other than the global scope (which all functions inherit).
// p is a global variableglobalThis.p = 5;function myFunc() { // p is a local variable const p = 9; function decl() { console.log(p); } const expr = function () { console.log(p); }; const cons = new Function("\tconsole.log(p);"); decl(); expr(); cons();}myFunc();// Logs:// 9 (for 'decl' by function declaration (current scope))// 9 (for 'expr' by function expression (current scope))// 5 (for 'cons' by Function constructor (global scope))
Functions defined by function expressions and function declarations are parsed only once, while a function defined by theFunction
constructor parses the string passed to it each and every time the constructor is called. Although a function expression creates a closure every time, the function body is not reparsed, so function expressions are still faster thannew Function(...)
. Therefore theFunction
constructor should generally be avoided whenever possible.
A function declaration may be unintentionally turned into a function expression when it appears in an expression context.
// A function declarationfunction foo() { console.log("FOO!");}doSomething( // A function expression passed as an argument function foo() { console.log("FOO!"); },);
On the other hand, a function expression may also be turned into a function declaration. Anexpression statement cannot begin with thefunction
orasync function
keywords, which is a common mistake when implementingIIFEs (Immediately Invoked Function Expressions).
function () { // SyntaxError: Function statements require a function name console.log("FOO!");}();function foo() { console.log("FOO!");}(); // SyntaxError: Unexpected token ')'
Instead, start the expression statement with something else, so that thefunction
keyword unambiguously starts a function expression. Common options includegrouping and usingvoid
.
(function () { console.log("FOO!");})();void function () { console.log("FOO!");}();
Function parameters
Each function parameter is a simple identifier that you can access in the local scope.
function myFunc(a, b, c) { // You can access the values of a, b, and c here}
There are three special parameter syntaxes:
- Default parameters allow formal parameters to be initialized with default values if no value or
undefined
is passed. - Therest parameter allows representing an indefinite number of arguments as an array.
- Destructuring allows unpacking elements from arrays, or properties from objects, into distinct variables.
function myFunc({ a, b }, c = 1, ...rest) { // You can access the values of a, b, c, and rest here}
There are some consequences if one of the above non-simple parameter syntaxes is used:
- You cannot apply
"use strict"
to the function body — this causes asyntax error. - Even if the function is not instrict mode, certain strict mode function features apply, including that the
arguments
object stops syncing with the named parameters,arguments.callee
throws an error when accessed, and duplicate parameter names are not allowed.
The arguments object
You can refer to a function's arguments within the function by using thearguments
object.
arguments
An array-like object containing the arguments passed to the currently executing function.
arguments.callee
The currently executing function.
arguments.length
The number of arguments passed to the function.
Getter and setter functions
You can define accessor properties on any standard built-in object or user-defined object that supports the addition of new properties. Withinobject literals andclasses, you can use special syntaxes to define the getter and setter of an accessor property.
- get
Binds an object property to a function that will be called when that property is looked up.
- set
Binds an object property to a function to be called when there is an attempt to set that property.
Note that these syntaxes create anobject property, not amethod. The getter and setter functions themselves can only be accessed using reflective APIs such asObject.getOwnPropertyDescriptor()
.
Block-level functions
Instrict mode, functions inside blocks are scoped to that block. Prior to ES2015, block-level functions were forbidden in strict mode.
"use strict";function f() { return 1;}{ function f() { return 2; }}f() === 1; // true// f() === 2 in non-strict mode
Block-level functions in non-strict code
In a word:Don't.
In non-strict code, function declarations inside blocks behave strangely. For example:
if (shouldDefineZero) { function zero() { // DANGER: compatibility risk console.log("This is zero."); }}
The semantics of this in strict mode are well-specified —zero
only ever exists within that scope of theif
block. IfshouldDefineZero
is false, thenzero
should never be defined, since the block never executes. However, historically, this was left unspecified, so different browsers implemented it differently in non-strict mode. For more information, see thefunction
declaration reference.
A safer way to define functions conditionally is to assign a function expression to a variable:
// Using a var makes it available as a global variable,// with closer behavior to a top-level function declarationvar zero;if (shouldDefineZero) { zero = function () { console.log("This is zero."); };}
Examples
Returning a formatted number
The following function returns a string containing the formatted representation of a number padded with leading zeros.
// This function returns a string padded with leading zerosfunction padZeros(num, totalLen) { let numStr = num.toString(); // Initialize return value as string const numZeros = totalLen - numStr.length; // Calculate no. of zeros for (let i = 1; i <= numZeros; i++) { numStr = `0${numStr}`; } return numStr;}
The following statements call thepadZeros
function.
let result;result = padZeros(42, 4); // returns "0042"result = padZeros(42, 2); // returns "42"result = padZeros(5, 4); // returns "0005"
Determining whether a function exists
You can determine whether a function exists by using thetypeof
operator. In the following example, a test is performed to determine if thewindow
object has a property callednoFunc
that is a function. If so, it is used; otherwise, some other action is taken.
if (typeof window.noFunc === "function") { // use noFunc()} else { // do something else}
Note that in theif
test, a reference tonoFunc
is used — there are no parentheses()
after the function name so the actual function is not called.
Specifications
Specification |
---|
ECMAScript® 2026 Language Specification # sec-function-definitions |