The function code has a slight impact on what declaration type to choose. Important is how the function interacts with the external components (the outer scope, the enclosing context, object that owns the method, etc) and the invocation type (regular function invocation, method invocation, constructor call, etc).

For instance you need this on a function invocation to be the same as the enclosing context (i.e. inherits this from the outer function). The best option is to use an arrow function, which provides the necessary context transparency.
The following example demonstrates that:

The arrow function passed to .every() has this (an instance of Names class) the same as contains() method. A function declared with the fat arrow is the most appropriate declaration type in a case when the context needs to be inherited from the outer method .contains().

If trying to use a function expression for .every() callback, it would require more manual configuration of the context. Available options are: set the second parameter of the .every(function(){...}, this) to indicate the context or use .bind() method on the callback function(){...}.bind(this). This is additional code and the arrow function provides the context transparency easier.

This post describes six approaches how to declare functions in JavaScript. Every type is explained in which situations it fits better and produces lighter code. Interested? Let’s get started.

1. Function declaration

A function declaration is made of function keyword, followed by an obligatory function name, a list of parameters in a pair of parenthesis (para1, ..., paramN) and a pair of curly braces {...} that delimits the body code.

function isEven(num) {...} is a function declaration that defines isEven function, which determines if a number is even.

The function declaration creates a variable in the current scope with the identifier equal to function name. This variable holds the function object.
The function variable is hoisted up to the top of the current scope, which means that the function can be invoked before the declaration.
Also the created function is named, which means that name property of the function object holds its name. It is useful when viewing the call stack: in debugging or error messages reading.
Let’s see these properties in an example:

The function declaration function hello(name) {...} create a variable hello that is hoisted to the top of the current scope. hello variable holds the function object andhello.name contains the function name: 'hello'.

1.1 A regular function

The function declaration matches for cases when a regular function should be created. Regular means that you declare the function once and later invoke it in many different places. This is the basic scenario:

Because the function declaration creates a variable in the current scope, alongside with regular function call, it is useful for recursion or detaching event listeners. Contrary to function expressions or arrow functions that do not create binding with the function variable by its name.
For example to calculate recursively the factorial:

Inside factorial() a recursive call is being made using the variable that holds the function: factorial(n - 1).
Of course is possible to use a function expression and assign it to a regular variable, e.g. var factorial = function(n) {...}. But the function declaration function factorial(n) looks more compact (no need for var and =).

An important property of the function declaration is its hoisting mechanism. It allows to use the function before declaration in the same scope.
Hoisting is useful in many cases. For instance when first you like to see how the function is called in the head of a script, without reading the details about function implementation. The function implementation can be situated below in the file and you may not even scroll there.
You can read more details about function declaration hoisting here.

1.3 Function declaration in conditionals

Some JavaScript environments can throw a reference error when invoking a function whose declaration appears within blocks {...} of if, for or while statements.
Let’s enable the strict mode and see what happens when a function is declared in a conditional:

When calling ok(), JavaScript throws ReferenceError: ok is not defined, because the function declaration is inside a conditional block.
Notice that this scenario works well in non-strict mode, which make it even more confusing.

As a general rule for these situations, when a function should be create based on some conditions – use a function expression. Let’s see how it is possible:

Because the function is a regular object, it is fine to assign it to a variable depending on a condition. Invoking ok() works fine and does not throw any errors.

2. Function expression

A function expression is determined by a function keyword, followed by an optional function name, a list of parameters in a pair of parenthesis (para1, ..., paramN) and a pair of curly braces { ... } that delimits the body code.
Some samples of the function expression usage:

The function expression creates a function object that can be used in different situations:

Assigned to a variable as an object count = function(...) {...}

Create a method on an object sum: function() {...}

Use the function as a callback .reduce(function(...) {...})

The function expression is the working horse in JavaScript. Most of the time developer deals with this type of function declaration alongside the arrow function (if you prefer short syntax and lexical context).

2.1 Named function expression

A function is anonymous when it does not have a name (name property is an empty string ''):

function funName(variable) {...} is a named function expression. The variablefunName is accessible within function scope, but not outside. The property name of the function object holds the name: funName.

2.2 Favor named function expression

When a variable assignment is used with a function expression var fun = function() {}, many engines can infer the function name from this variable. Often callbacks are passed as anonymous function expressions, without storing into variables: so the engine cannot determine its name.

In many situations it seems reasonable to use named functions and avoid anonymous ones. This brings a series of benefits:

The error messages and call stacks show more detailed information when use the function names

More comfortable debugging by reducing the number of anonoymous stack names

The function name helps to understand quickly what it does

It is possible to access the function by name inside its scope for recursive calls or detaching event listeners

3. Shorthand method definition

Shorthand method definition can be used in a method declaration on object literals and ES6 classes. You can define them using a function name, followed by a list of parameters in a pair of parenthesis (para1, ..., paramN) and a pair of curly braces { ... } that delimits the body statements.

The following example uses shorthand method definition in an object literal:

3.1 Computed property names and methods

ECMAScript 6 adds a nice feature: computed property names in object literals and classes.
The computed properties use a slight different syntax [methodName]() {...}, so the method definition looks this way:

4. Arrow function

An arrow function is defined using a pair of parenthesis that contains the list of parameters (param1, param2, ..., paramN), followed by a fat arrow => and a pair of curly braces {...} that delimits the body statements.
When the arrow function has only one parameter, the pair of parenthesis can be omitted. When it contains a single statement, the curly braces can be omitted too.

absValue is an arrow function that calculates the absolute value of a number.

The function declared using a fat arrow has the following properties:

The arrow function does not create its own execution context, but takes it lexically (contrary to function expression or function declaration, which create own this depending on invocation)

The arrow function is anonymous: name is an empty string (contrary to function declaration which have a name)

arguments object is not available in the arrow function (contrary to other declaration types that provide arguments object)

4.1 Context transparency

this keyword is one of the most confusing aspects of JavaScript.
Because functions create their own execution context, often it is hard to catch the flying around this.

ECMAScript 6 improves this usage by introducing the arrow function, which takes the context lexically. This is nice, because from now on is not necessary to use.bind(this) or store the context var self = this when a function needs the enclosing context.

Numbers class holds an array of numbers and provides a method addNumber() to insert new numbers.
When addNumber() is called without arguments, a closure is returned that allows to insert numbers. This closure is an arrow function which has this as numbersObjectinstance, because the context is taken lexically from addNumbers() method.

Without the arrow function is necessary to manually fix the context. It means adding fixes by using .bind() method:

Sometimes nested short arrow functions are difficult to read. So the most convinient way to use the short form is a single callback function (without nested ones).
If necessary, in the nested functions the optional curly braces can be restored to increase the readability.

5. Generator function

The generator function in JavaScript returns a Generator object. Its syntax is similar to function expression, function declaration or method declaration, just that it requires a star character *.

The function object type has a constructor: Function.
When Function is invoked as a constructor new Function(arg1, arg2, ..., argN, bodyString), a new function is created. The arguments arg1, args2, ..., argN passed to constructor become the parameter names for the new function and the last argument bodyString is used as the function body code.

Important to remember about new Function is that almost never functions should be declared this way. Because the function body is evaluated on runtime, this approach inherits many eval() usage problems: security risks, harder debugging, no way to apply interpreter optimizations, no code auto-complete.

7. In the end, which way is better?

There is no winner or looser. The decision which declaration type to choose depends on the situation.

There are some rules however that you may follow for common situations.

If the function should use this from the enclosing function, the arrow function is a good solution. When the callback function has one short statement, the arrow function is a good option too, because it creates short and light code.

For a shorter syntax when declaring methods on object literals, the shorthand method declaration is preferable.

new Function way to declare functions generally should not be used. Mainly because it opens potential security risks, doesn’t allow code auto-complete in editors and lose the engine optimizations.

I believe this article is another step to write more readable and less buggy functions. Especially because they are the living cells of any application.