Generally, a function is a sequence of instructions or a 'subprogram' that can be invoked by the code that is external (or internal) to that function. In essence, functions 'encapsulate' a particular task.
Function object. You can go into the console and try this out.
Function object has a few specific methods and properties like
isGenerator, etc. that are not available on other Objects.
This might be the most familiar way of defining a function. A function declaration consists of a name preceded by the mandatory
function keyword and followed by an optional list of parameters inside a required pair of parenthesis
Two main things to be noted about this form of defining a function are:
A variable which holds the function object is created in the current scope with the same identifier as the function name provided. In our example,
The variable is hoisted to the top of the current scope. You can read more on that here.
To bring the second point home, lets look at an example :
We were able to invoke the function
notYetDeclared before we defined it.
A function expression is very similar in syntax to a function declaration. The major difference is that a function expression does not need a function name.
Function expressions are a part of another statement. In the example above, the function expression is part of the
sum variable assignment.
Unlike function declaration, function expressions are not hoisted.
An interesting use-case of Function Expressions is the ability to create IIFEs or Immediately Invoked Function Expressions. There are instances where we might want to define a function and invoke it right after the definition and never again. Sure, it can be done with function declaration but to make it more readable and to make sure that our program doesn't accidentally access it, we use an IIFE.
Consider this example,
We create a function called
callImmediately which takes an argument and logs it and then we immediately call it. This same result can be achieved by doing this.
The key difference is that in the first case, the function declaration pollutes the global namespace and the named function
callImmediately hangs around long after it is required. The IIFE is anonymous and hence cannot be called in the future.
Arrow functions are an ES6 addition and are meant as a syntactically compact alternative to Function Expressions. Arrow functions are defined using a pair of parenthesis containing a list of parameters, followed by a fat arrow
=> and then the function statements with curly braces
Since one of the main motivations behind the arrow function is syntax compactness, if the only statement in the arrow function is
return we can remove both the curly braces and the
return keyword, like so :
Also the parens can be eliminated if we have only one parameter being passed to the arrow function.
Some important things to note in this form of function definition are :
An arrow function does not have its own
thisand it uses the
thisvalue of the enclosing lexical scope.
In the above example, we have an arrow function and a function expression that logs
An arrow function does not have the
argumentsobject is not available in an arrow function. You can read more about the
Function object so to define a function we can also directly call the constructor of the
The arguments are passed as a list of comma separated strings
'param1', 'param2', ..., 'paramN' and the last argument is the function body passed in as a string.
Performance wise, this way of defining a function is less efficient than function declaration or function expression. Functions defined using Function constructor are parsed each time the constructor is called because the function body string needs to be parsed each time unlike others which are parsed with the rest of the code.
One use-case of defining functions this way is to access the
global object in node or the
window object in the browser. These functions are always created in the global scope and do not have access to the current scope.
Generators are an ES6 addition. Generators are special types of functions in the sense that unlike a traditional function, generators produce multiple values on a per request basis while suspending their execution between these requests.
yield keywords are unique to a generator. Generators are defined by adding an
* at the end of a function keyword. This enables us to use the
yield keyword within the body of the generator to produce values on request.
You can read it in more detail here.
The choice of which definition type to use is dependent on the situation and what you are trying to achieve. A few general pointers to keep in mind:
If you want to leverage function hoisting use function declarations - for example in situations where you want to move the function implementation details to the bottom and just the abstracted flow on top for clarity.
Arrow functions are well suited for short callback functions and more importantly, when the desired
thisis the enclosing function.
Avoid using the Function constructor to define functions. If the annoying syntax wasn't enough to keep you away, it could potentially be a risk from a security standpoint.