Function Expression

Summary

Defines a function inside an expression.

Syntax

returntype [name]([[type1] param1 [, [type2] param2 ... [, [...] [type3] param3]]]) {
    statement1;
    statement2;
    statement3;
}

Parameters

returntype
The type to restrict the expression for the return statement to.
name
The name of the function. This can be any valid identifier. Optional for function expressions.
typeN
The type to restrict the parameter to.
paramN
The name for the parameter. This can be any valid identifier. Optionally, a variadic parameter can be created by prefixing the parameter with ...
statementN
The statement(s) to execute when the function is called.

Description

A function is a named set of instructions that can be executed over and over again with different possible inputs. Functions are commonly used for performing a specific task, and they can return a value. The value returned by a function is known as its return value, and the type of the return value is known as the return type.

The parameters for a function define the inputs for the function. Functions can be called with different inputs ("arguments") each time.

Functions can also return a value via the return statement. The return value can be any valid expression. When the function is called, the function call expression is replaced with the return value.

Overview

Function Declaration vs. Function Expression

A function can be either A) a function declaration and used where a statement is expected, or B) a function expression and used where an expression is expected.

Function Declaration
1
2
3
4
5
function foo() {
    return true;
}
 
foo();
Function Expression
1
2
3
4
5
var foo = function foo() {
    return true;
};
 
foo();

Thus, when used as an expression, functions can be passed to another function as an argument, returned from a function, or assigned to variables.

Assigning Function to Variable
1
2
3
var foo = function() {
    return true;
};
Returning a Function from a Function
1
2
3
4
5
6
7
8
9
10
function foo() {
    return function() {
        return 100;
    };
}
 
// Call twice.
// The first call returns the returned function, which gets called again,
// producing the result: 100
foo()();
Passing a Function as an Argument
1
2
3
4
5
6
7
function foo(bar) {
    return bar(); // returns 100
}
 
foo(function() {
    return 100;
});

In addition, a function expression can be immediately executed (IIFE - immediately-invoked function expression):

1
2
3
(function() {
    // Do something...
})();

In JavaScript, IIFEs were used to create a scope. However, with the scoping rules of JS++ (and especially its file scope), creating a scope with an IIFE is unnecessary.

Anonymous Functions

Function expressions can be anonymous functions. In other words, the function expression can be created without a name.

If the anonymous expression is assigned to a variable, it can be called using the variable's name.

Anonymous Function Assigned to Variable
1
2
3
4
5
var foo = function() { // this function was declared without a name
    return true;
};
 
foo(); // call using the name of the variable the function was assigned to
Anonymous Function Passed as Argument
1
2
3
4
5
6
7
function foo(bar) {
    bar(); // call using the name of the parameter the function was assigned to
}
 
foo(function() { // pass an anonymous function to 'foo'
    return true;
});

Note that function declarations cannot be anonymous and must always be declared with a name.

Parameters and Arguments

Variadic Parameters

Variadic parameters allow a function to take infinitely many arguments for a single parameter. The arguments supplied to the variadic parameter are stored as an array. To make a parameter a variadic parameter, prefix the parameter with ...

1
2
3
4
5
6
7
8
9
10
11
function add(...numbers) {
    int total = 0;
    foreach(int number in numbers) {
        total += number;
    }
     
    return total;
}
 
add(1, 2, 3); // 6
add(4, 5, 6); // 15

Only one variadic parameter is allowed for each function.

Callback Parameters

Parameters can have a callback type:

1
2
3
4
5
6
7
8
9
import System;
 
void message(int(int, int) callback) { // 'callback' has type 'int(int, int)'
    Console.log(add(1, 2));
}
 
message(int add(int firstNumber, int secondNumber) {
    return firstNumber + secondNumber;
});

In the above example, the message function takes one parameter which has a callback type. The parameter expects a callback that returns type int and takes two int parameters.

When we call the message function, we send an argument that is a callback. The callback we send to the function matches the function signature expected for the callback parameter. In the example, we send an add callback function as an argument, and, when the message function calls the callback with the arguments 1 and 2, the add callback will execute, add the two numbers together, and return it.

Overloading

Function expressions cannot be overloaded.

Closures

A closure is created when a function is declared inside another function. The inner function can access the variables and parameters of the outer function (even after the outer function returns).

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
function foo(z) {
    int x = 1;
     
    function bar() {
        int y = 1;
         
        return x + y + z;
    }
     
    return bar();
}
 
foo(1); // 3

We can also rewrite the example so the inner function gets returned for the outer function, and, despite the outer function having returned already, the returned inner function can still access the variables and parameters of the outer function:

1
2
3
4
5
6
7
8
9
10
11
function foo(z) {
    int x = 1;
     
    return function bar() {
        int y = 1;
         
        return x + y + z;
    };
}
 
foo(1)(); // Call twice since first function returns a function. Result is: 3

Be careful with closures as they can be a source of memory leaks. For more information, consult the closures documentation for closure memory leaks.

See Also

Share

HTML | BBCode | Direct Link