To create a function we can use a function declaration.
function showMessage() { alert( 'Hello everyone!' ); }
The function keyword goes first, then goes the name of the function, then a list of parameters between the parentheses (empty in the example above) and finally the code of the function, also named “the function body”, between curly braces.
Our new function can be called by its name: showMessage()
.
function showMessage() { alert( 'Hello everyone!' ); } showMessage(); showMessage();
The call showMessage()
executes the code of the function. Here we will see the message two times.
A variable declared inside a function is only visible inside that function.
function showMessage() { let message = "Hello, I'm JavaScript!"; // local variable alert( message ); } showMessage(); // Hello, I'm JavaScript! alert( message ); // <-- Error! The variable is local to the function
A function can access an outer variable as well, for example:
let userName = 'John'; function showMessage() { let message = 'Hello, ' + userName; alert(message); } showMessage(); // Hello, John
The function has full access to the outer variable. It can modify it as well.
let userName = 'John'; function showMessage() { userName = "Bob"; // (1) changed the outer variable let message = 'Hello, ' + userName; alert(message); } alert( userName ); // John before the function call showMessage(); alert( userName ); // Bob, the value was modified by the function
If a same-named variable is declared inside the function then it shadows the outer one. For instance, in the code below the function uses the local userName
. The outer one is ignored:
let userName = 'John'; function showMessage() { let userName = "Bob"; // declare a local variable let message = 'Hello, ' + userName; // Bob alert(message); } // the function will create and use its own userName showMessage(); alert( userName ); // John, unchanged, the function did not access the outer variable
Variables declared outside of any function, such as the outer userName
in the code above, are called global.
Global variables are visible from any function (unless shadowed by locals).
We can pass arbitrary data to functions using parameters (also called function arguments). In the example below, the function has two parameters: from
and text
.
function showMessage(from, text) { // arguments: from, text alert(from + ': ' + text); } showMessage('Ann', 'Hello!'); // Ann: Hello! (*) showMessage('Ann', "What's up?"); // Ann: What's up? (**)
When the function is called in lines (*) and (**), the given values are copied to local variables from and text. Then the function uses them.
Here’s one more example: we have a variable from and pass it to the function. Please note: the function changes from, but the change is not seen outside, because a function always gets a copy of the value:
function showMessage(from, text) { from = '*' + from + '*'; // make "from" look nicer alert( from + ': ' + text ); } let from = "Ann"; showMessage(from, "Hello"); // *Ann*: Hello // the value of "from" is the same, the function modified a local copy alert( from ); // Ann
If a parameter is not provided, then its value becomes undefined.
For instance, the aforementioned function showMessage(from, text)
can be called with a single argument:
showMessage("Ann");
That’s not an error. Such a call would output "Ann: undefined"
. There’s no text, so it’s assumed that text === undefined
.
If we want to use a “default” text in this case, then we can specify it after =
:
function showMessage(from, text = "no text given") { alert( from + ": " + text ); } showMessage("Ann"); // Ann: no text given
Now if the text
parameter is not passed, it will get the value "no text given"
Here "no text given"
is a string, but it can be a more complex expression, which is only evaluated and assigned if the parameter is missing. So, this is also possible:
function showMessage(from, text = anotherFunction()) { // anotherFunction() only executed if no text given // its result becomes the value of text }
A function can return a value back into the calling code as the result.
function sum(a, b) { return a + b; } let result = sum(1, 2); alert( result ); // 3
The directive return
can be in any place of the function. When the execution reaches it, the function stops, and the value is returned to the calling code.
There may be many occurrences of return in a single function. For instance:
function checkAge(age) { if (age > 18) { return true; } else { return confirm('Got a permission from the parents?'); } } let age = prompt('How old are you?', 18); if ( checkAge(age) ) { alert( 'Access granted' ); } else { alert( 'Access denied' ); }
It is possible to use return without a value. That causes the function to exit immediately.
function showMovie(age) { if ( !checkAge(age) ) { return; } alert( "Showing you the movie" ); // (*) // ... }
In the code above, if checkAge(age)
returns false
, then showMovie
won’t proceed to the alert
.
A function with an empty return or without it returns undefined
If a function does not return a value, it is the same as if it returns undefined
:
function doNothing() { /* empty */ } alert( doNothing() === undefined ); // true
An empty return
is also the same as return undefined
:
function doNothing() { return; } alert( doNothing() === undefined ); // true
There is another syntax for creating a function that is called a Function Expression.
let sayHi = function() { alert( "Hello" ); };
Here, the function is created and assigned to the variable explicitly, like any other value. No matter how the function is defined, it’s just a value stored in the variable sayHi
.
The meaning of these code samples is the same: "create a function and put it into the variable sayHi".
We can even print out that value using alert:
function sayHi() { alert( "Hello" ); } alert( sayHi ); // shows the function code
Please note that the last line does not run the function, because there are no parentheses after sayHi. There are programming languages where any mention of a function name causes its execution, but JavaScript is not like that. In JavaScript, a function is a value, so we can deal with it as a value. The code above shows its string representation, which is the source code.
It is a special value of course, in the sense that we can call it like sayHi()
.
But it’s still a value. So we can work with it like with other kinds of values.
function sayHi() { // (1) create alert( "Hello" ); } let func = sayHi; // (2) copy func(); // Hello // (3) run the copy (it works)! sayHi(); // Hello // this still works too (why wouldn't it)
In the above example, we are copying sayHi
to func
, in this case the reference to the function is gets copied to the func
. So, both refers to the same function. So the call func()
and sayHi()
executes the same function and you will get the same result.
A Function Expression is used inside the statement: let sayHi = ...;
, as a value. It’s not a code block. The semicolon ;
is recommended at the end of statements, no matter what is the value. So the semicolon here is not related to the Function Expression itself in any way, it just terminates the statement.
Let’s look at more examples of passing functions as values and using function expressions. In the following example, the function asks the question and, depending on the user’s answer, call yes() or no():
function ask(question, yes, no) { if (confirm(question)) yes() else no(); } function showOk() { alert( "You agreed." ); } function showCancel() { alert( "You canceled the execution." ); } // usage: functions showOk, showCancel are passed as arguments to ask ask("Do you agree?", showOk, showCancel);
The last two arguments of ask
are called callback functions or just callbacks.
The idea is that we pass a function and expect it to be “called back” later if necessary. In our case, showOk
becomes the callback for the “yes” answer, and showCancel
for the “no” answer.
We can use Function Expressions to write the same function much shorter:
function ask(question, yes, no) { if (confirm(question)) yes() else no(); } ask( "Do you agree?", function() { alert("You agreed."); }, function() { alert("You canceled the execution."); } );
Here, functions are declared right inside the ask(...)
call. They have no name, and so are called anonymous
. Such functions are not accessible outside of ask (because they are not assigned to variables), but that’s just what we want here.
Here are some difference between these two -
Function Declaration
: a function, declared as a separate statement, in the main code flow.
// Function Declaration function sum(a, b) { return a + b; }
Function Expression
: a function, created inside an expression or inside another syntax construct. Here, the function is created at the right side of the “assignment expression” =:
// Function Expression let sum = function(a, b) { return a + b; };
A Function Declaration is usable in the whole script/code block.
In other words, when JavaScript prepares to run the script or a code block, it first looks for Function Declarations in it and creates the functions. We can think of it as an “initialization stage”. And after all of the Function Declarations are processed, the execution goes on. As a result, a function declared as a Function Declaration can be called earlier than it is defined. For example, this works:
sayHi("John"); // Hello, John function sayHi(name) { alert( `Hello, ${name}` ); }
The Function Declaration sayHi
is created when JavaScript is preparing to start the script and is visible everywhere in it. If it was a Function Expression, then it wouldn’t work:
sayHi("John"); // error! let sayHi = function(name) { alert( `Hello, ${name}` ); };
A Function Expression is created when the execution reaches it and is usable from then on.
When a Function Declaration is made within a code block, it is visible everywhere inside that block. But not outside of it.
let age = prompt("What is your age?", 18); // conditionally declare a function if (age < 18) { function welcome() { alert("Hello!"); } } else { function welcome() { alert("Greetings!"); } } // ...use it later welcome(); // Error: welcome is not defined
What can we do to make welcome visible outside of if
?
The correct approach would be to use a Function Expression and assign welcome to the variable that is declared outside of if
and has the proper visibility.
Now it works as intended:
let age = prompt("What is your age?", 18); let welcome; if (age < 18) { welcome = function() { alert("Hello!"); }; } else { welcome = function() { alert("Greetings!"); }; } welcome(); // ok now
Or we could simplify it even further using conditional operator :
let age = prompt("What is your age?", 18); let welcome = (age < 18) ? function() { alert("Hello!"); } : function() { alert("Greetings!"); }; welcome(); // ok now
There’s one more very simple and concise syntax for creating functions, that’s often better than Function Expressions. It’s called “arrow functions”, because it looks like this:
let func = (arg1, arg2, ...argN) => expression
This creates a function func that has arguments arg1..argN, evaluates the expression on the right side with their use and returns its result. The above syntax is same as -
let func = function(arg1, arg2, ...argN) { return expression; };
Here is an example -
let sum = (a, b) => a + b; /* The arrow function is a shorter form of: let sum = function(a, b) { return a + b; }; */ alert( sum(1, 2) ); // 3
If we have only one argument, then parentheses can be omitted, making that even shorter:
// same as // let double = function(n) { return n * 2 } let double = n => n * 2; alert( double(3) ); // 6
If there are no arguments, parentheses should be empty (but they should be present):
let sayHi = () => alert("Hello!"); sayHi();
Arrow functions can be used in the same way as Function Expressions. For instance, here’s the rewritten example with welcome()
:
let age = prompt("What is your age?", 18); let welcome = (age < 18) ? () => alert('Hello') : () => alert("Greetings!"); welcome(); // ok now
The above examples of the arrow function has simple one expression and the evaluated value of that expression gets returned. Sometimes we need something a little bit more complex, like multiple expressions or statements. It is also possible, but we should enclose them in curly braces. Then use a normal return within them.
let sum = (a, b) => { // the curly brace opens a multiline function let result = a + b; return result; // if we use curly braces, use return to get results }; alert( sum(1, 2) ); // 3