When to use arrow functions instead of regular functions in utils
Arrow functions have different behavior than function declarations / expressions, so lets have a look at the differences first:
Lexical this and arguments
Arrow functions don't have their own this or arguments binding. Instead, those identifiers are resolved in the lexical scope like any other variable. That means that inside an arrow function, this and arguments refer to the values of this and arguments in the environment the arrow function is defined in (i.e. "outside" the arrow function):
Arrow functions cannot be called with new
ES2015 distinguishes between functions that are callable and functions that are constructable. If a function is constructable, it can be called with new, i.e. new User(). If a function is callable, it can be called without new (i.e. normal function call).
Functions created through function declarations / expressions are both constructable and callable.
Arrow functions (and methods) are only callable. class constructors are only constructable. And Lots of other things matter like Callback,prototype etc
Purpose of using arrow function and function keyword syntax together?
I think that this is just inconsistent coding style, the end result is virtually the same (although in some instances you might be unable to use arrow functions) so it doesn't really matter.
Some developers like to use arrow functions, others like to use normal functions.
Sometimes you might forget to use an arrow function, or are copying someone else's code and forget to reformat it to your own coding style.
If this bugs you out, you can use ESLint to enforce a consistent style for your project.
Are there performance gains in using ES6 Arrow Functions?
Keep in mind there can’t be an universal answer to this question, as always with all of which is implementation dependant. So the answer may be X now or with some browsers, and may be Y in the future or with other browsers.
These provisions said, here are some data: http://incaseofstairs.com/six-speed. For now and with major browsers, the answer is rather No and there might even be performance penalties (under the above provisions).
When should I use a return statement in ES6 arrow functions
Jackson has partially answered this in a similar question:
Implicit return, but only if there is no block.
- This will result in errors when a one-liner expands to multiple lines and the programmer forgets to add a
return
.- Implicit return is syntactically ambiguous.
(name) => {id: name}
returns the object{id: name}
... right? Wrong. It returnsundefined
. Those braces are an explicit block.id:
is a label.
I would add to this the definition of a block:
A block statement (or compound statement in other languages) is used to group zero or more statements. The block is delimited by a pair of curly brackets.
Examples:
// returns: undefined
// explanation: an empty block with an implicit return
((name) => {})()
// returns: 'Hi Jess'
// explanation: no block means implicit return
((name) => 'Hi ' + name)('Jess')
// returns: undefined
// explanation: explicit return required inside block, but is missing.
((name) => {'Hi ' + name})('Jess')
// returns: 'Hi Jess'
// explanation: explicit return in block exists
((name) => {return 'Hi ' + name})('Jess')
// returns: undefined
// explanation: a block containing a single label. No explicit return.
// more: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label
((name) => {id: name})('Jess')
// returns: {id: 'Jess'}
// explanation: implicit return of expression ( ) which evaluates to an object
((name) => ({id: name}))('Jess')
// returns: {id: 'Jess'}
// explanation: explicit return inside block returns object
((name) => {return {id: name}})('Jess')
Methods in ES6 objects: using arrow functions
Arrow functions are not designed to be used in every situation merely as a shorter version of old-fashioned functions. They are not intended to replace function syntax using the function
keyword. The most common use case for arrow functions is as short "lambdas" which do not redefine this
, often used when passing a function as a callback to some function.
Arrow functions cannot be used to write object methods because, as you have found, since arrow functions close over the this
of the lexically enclosing context, the this
within the arrow is the one that was current where you defined the object. Which is to say:
// Whatever `this` is here...
var chopper = {
owner: 'Zed',
getOwner: () => {
return this.owner; // ...is what `this` is here.
}
};
In your case, wanting to write a method on an object, you should simply use traditional function
syntax, or the method syntax introduced in ES6:
var chopper = {
owner: 'Zed',
getOwner: function() {
return this.owner;
}
};
// or
var chopper = {
owner: 'Zed',
getOwner() {
return this.owner;
}
};
(There are small differences between them, but they're only important if you use super
in getOwner
, which you aren't, or if you copy getOwner
to another object.)
There was some debate on the es6 mailing list about a twist on arrow functions which have similar syntax but with their own this
. However, this proposal was poorly received because that is mere syntax sugar, allowing people to save typing a few characters, and provides no new functionality over existing function syntax. See the topic unbound arrow functions.
What are the advantages/disadvantages for creating a top level function in ES6 with arrows or without?
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;
}
- Hoisted (because it's a function declaration).
- Until ES2015 (ES6), only valid at global scope or at the top-level of a function; ES2015+ allows them within control flow statements, but the rules are complex.
- Can be overwritten later via
square = ...
(or a later function declaration). - Creates an object and assigns it to
square.prototype
, even though we don't intend it to be a constructor. (Note: I'm told by a member of the V8 team that V8, at least, doesn't do this until/unless the property's value is actually used. Other engines probably do something similar. So this doesn't really matter much.) - Attempts to use it as a constructor (
new square
) will work, but probably not do what the coder expected: The result of thenew
operation will be an object usingsquare.prototype
as its prototype (and the function's return value fromn * n
is thrown away). - If at global scope, creates a property on the global object (and thus, a global) because it's a function declaration.
- If
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;
};
- Not hoisted (because it's an expression), created during control flow.
- Until ES2015, since it's an anonymous function expression, the function didn't have a name. In ES2015+, the name is derived from the variable's name (browser support may lag a bit, it seems to be low on the ES2015 support priority list).
- Can be overwritten later via
square = ...
- Creates an object and assigns it to
square.prototype
, even though we don't intend it to be a constructor. (Note: Again, V8, at least, doesn't do this until/unless the property is used.) - Attempts to use it as a constructor (
new square
) will work, but probably not do what the coder expected (see note on the function declaration). - If at global scope, creates a property on the global object (and thus, a global) since it's an old-style
var
variable. - If
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;
- Not hoisted (because it's an expression), created during control flow.
- The function's name is derived from the variable's name (browser support may lag a bit, it seems to be low on the ES2015 support priority list).
- Can be overwritten later via
square = ...
- Doesn't create an object and assign it to
square.prototype
. (Though again, JavaScript engines probably avoided that anyway.) - Attempts to use it as a constructor (
new square
) will fail with an informative error (TypeError: square is not a constructor
). - Doesn't have
arguments
(but you can use rest arguments instead if you needarguments
functionality). - Per spec, requires fewer things to be "set up" when calling it, as it doesn't have its own
this
and doesn't havearguments
. But modern JavaScript engines already optimize-out the creation ofarguments
if you don't use it, and it's unlikely setting upthis
is a significant cost. - If at global scope, creates a property on the global object (and thus, a global) since it's an old-style
var
variable. - Because it's an arrow function, if
this
were used within the function, it would use the samethis
as the code where the function is defined, since arrow functions close overthis
(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;
- Not hoisted, created during control flow
- The function's name is derived from the variable's name (browser support may lag a bit, it seems to be low on the ES2015 support priority list).
- Can't be overwritten later via
square = ...
- Doesn't create an object and assign it to
square.prototype
. - Attempts to use it as a constructor (
new square
) will fail with an informative error (TypeError: square is not a constructor
). - Doesn't have
arguments
(see notes on Option 3). - Per spec, requires fewer things to be "set up" when calling it (see notes on Option 3).
- If at global scope, doesn't create a property on the global object (but still creates a global), since it's an ES2015+
const
. - Because it's an arrow function, if
this
were used within the function, it would use the samethis
as the code where the function is defined, since arrow functions close overthis
(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 = ...
this keyword in arrow function
Arrow functions have a lexical this
which means that the value of this
inside the function is the same as the value of this
outside the function.
It does not mean that this
points to an object containing all the variables from outside the function.
const anObject = {
aValue: "example value",
aMethod: function() {
console.log("aMethod", this.aValue);
const arrow = () => {
console.log("arrow", this.aValue);
}
arrow();
}
}
anObject.aMethod();
const copyOfAMethod = anObject.aMethod;
copyOfAMethod();
Are there cases in modern JavaScript where arrow functions cannot be used where bind was previously used?
I see 2 advantages:
Partial Application:
The bind method can be used to pre-set a function's arguments; it sort of lets you create a sub-function of a function (not literally, behind-the-scenes, there will be only one function) by passing an argument before making the call, so that this argument you have preset will be used for all invocations of the function returned by bind. @Charlie_H has already explained this, but I am going to provide an example as well:
function foo(bar, baz) {
return bar + baz;
}
var sub_foo = foo.bind(Object.create(null), 20);
console.log(sub_foo(60));
console.log(sub_foo(120));
So as you can see in the above example, the bind
method allowed me to create what you could call a sub-function off of foo
, this function will always use 20
for its first parameter.
Now again, don't let my poor wording misguide you, bind
does not actually create a new function! behind-the-scenes, the original function will be used, the only thing is bind
will perform some of its magic so that the parameter you passed to bind
is always used. I am using the word "sub-function" because it makes the whole thing easier to understand.
Ability to bind the this
of the target function to whatever object you want:
With fat-arrow functions, the this
of the fat-arrow function will always be bound to the this
of the enclosing scope; with bind, you can bind the target function's this
to any object you want:
function foo() {
return this.baz;
}
var bar = foo.bind({baz: "Hell yeah!"});
bar(); // "Hell yeah!"
Moreover, the this
binding of fat-arrow functions is not overridable, this is a subtle detail but still useful.
One more thing i want to add, in the book You Don't Know JS: this & Object Prototypes, Kyle Simpson says that you should not use fat-arrow functions to get around this
complexities, which sort of bends JavaScript's this
rules, since their usage roots back to the var self = this
pattern, and that pattern's usage stems from a lack of understanding of JavaScript's this
behavior. Short version: he prefers bind
.
I don't see anything with using fat-arrow functions though, IMO they even make code more readable since just by looking at them you can see what the developer is trying to do and how they've used that, meanwhile, with bind
, you don't know exactly what the developer is trying to do and why they're doing it until you look at bind
's first argument. I recommend fat-arrow functions where you want the this
of the fat-arrow function to be bound to the current scope's this
, and bind
when you want it bound to something else.
If you don't understand parts of my answer, ask me and I will try to elaborate in the comments.
is it possible to write an es6 onChange arrow function?
I was just wondering if it was possible to have a multi line function embedded in the html. Appears the answer is n
You can. The value of the on*
attributes become the body of a function. Therefore you can define a function inline but you also have to call it.
For example:
<select onChange="function foo(){
console.log('hello')
}
foo();">
<option value="5"> 5</option>
<option value="10">10</option>
<option value="15">15</option>
</select>
<!-- as IIFE -->
<select onChange="(function(){console.log('hello')}())">
<option value="5"> 5</option>
<option value="10">10</option>
<option value="15">15</option>
</select>
<!-- of course that works with arrow functions too -->
<select onChange="(() => {console.log('hello')
console.log('goodbye')})()">
<option value="5"> 5</option>
<option value="10">10</option>
<option value="15">15</option>
</select>
Related Topics
How to Get the Full Object in Node.Js'S Console.Log(), Rather Than '[Object]'
How to Add Options to a Select from a JavaScript Object With Jquery
How to Reload a Page Using JavaScript
Fastest Way to Duplicate an Array in JavaScript - Slice Vs. 'For' Loop
JavaScript Variable Number of Arguments to Function
How to Execute a JavaScript Function When I Have Its Name as a String
Window.Onload VS $(Document).Ready()
How to Manage a Redirect Request After a Jquery Ajax Call
How to Use the : (Conditional) Operator in JavaScript
Convert a JavaScript String in Dot Notation into an Object Reference
Difference Between a Function Call and Function Reference
How to Replace Plain Urls With Links
Jquery: Return Data After Ajax Call Success
How to Do Case Insensitive String Comparison