What are the advantages/disadvantages to create a top level function in ES6/ES2015 in those different ways? Or is this just a matter of taste/style guide etc?
Option 1:
function square(n) {
return n * n;
}
Option 2:
var square = function(n) {
return n * n;
};
Option 3:
var square = (n) => {
return n * n;
};
Option 4:
const square = (n) => {
return n * n;
};
An arrow function doesn't have its own this value and the arguments object. Therefore, you should not use it as an event handler, a method of an object literal, a prototype method, or when you have a function that uses the arguments object.
There are two major benefits of using Arrow functions. One is that it's a shorter syntax and thus requires less code. The main benefit is that it removes the several pain points associated with the this operator.
Unlike regular functions, arrow functions do not have their own this . Arguments objects are not available in arrow functions, but are available in regular functions. Regular functions created using function declarations or expressions are 'constructible' and 'callable'.
The takeaway: Function expressions are best for object methods. Arrow functions are best for callbacks or methods like map, reduce, or forEach. You can read more about scopes on MDN. On a fundamental level, arrow functions are simply incapable of binding a value of this different from the value of this in their scope.
Note: I've posted this as a community wiki, we can all add to the list, clarify, etc. Please no opinions. Keep it objective.
Or is this just a matter of taste/style guide etc?
There will be a strong influence of style, yes, but there are some objective observations we can make in terms of the functionality and runtime characteristics of the options that can be used to decide which is appropriate for a given use-case.
Option 1:
function square(n) { return n * n; }
square = ...
(or a later function declaration).square.prototype
, even though we don't intend it to be a constructor.new square
) will work, but probably not do what the coder expected: The result of the new
operation will be an object using square.prototype
as its prototype (and the function's return value from n * n
is thrown away).this
were used within the function, it would be determined by how the function is called, as it's a "normal" function.Option 2:
var square = function(n) { return n * n; };
square = ...
square.prototype
, even though we don't intend it to be a constructor.new square
) will work, but probably not do what the coder expected (see note on the function declaration).var
variable.this
were used within the function, it would be determined by how the function is called, as it's a "normal" function.Option 2.5: (I've added this one)
var square = function square(n) { return n * n; };
Exactly like Option 2, except that on ES5 and earlier, the function has a true name (square
). (Note that the name doesn't have to be the same as the name of the variable, although it is in this example.) (Bugs in IE8 and earlier would end up creating two functions instead of just one; details in this blog post by T.J. Crowder [principal author of this answer].)
Option 3:
var square = (n) => { return n * n; };
Could also be written:
var square = n => n * n;
square = ...
square.prototype
.new square
) will fail with an informative error (TypeError: square is not a constructor
).arguments
(but you can use rest arguments instead if you need arguments
functionality).this
and doesn't have arguments
. But modern JavaScript engines already optimize-out the creation of arguments
if you don't use it, and it's unlikely setting up this
is a significant cost.var
variable.this
were used within the function, it would use the same this
as the code where the function is defined, since arrow functions close over this
(rather than having it set by how they're called).Option 4:
const square = (n) => { return n * n; };
Could also be written:
const square = n => n * n;
square = ...
square.prototype
.new square
) will fail with an informative error (TypeError: square is not a constructor
).arguments
(see notes on Option 3).const
.this
were used within the function, it would use the same this
as the code where the function is defined, since arrow functions close over this
(rather than having it set by how they're called).Option 5: (I've added this one)
let square = (n) => { return n * n; };
Could also be written:
let square = n => n * n;
Exactly like Option 4, except it can be overwritten later via square = ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With