I have been trying to understand es6 arrow function. I read some articles introducing it. But I'am still not getting it fully.
For example I have this code:
sortedArticles(): Article[] {
return this.articles.sort((a: Article, b: Article) => b.votes - a.votes);
}
It sorts the below array:
[
new Article('Angular 2', 'http://angular.io', 3),
new Article('Fullstack', 'http://fullstack.io', 2),
new Article('Angular Homepage', 'http://angular.io', 1),
];
How would the same code look in plain old js? I am not able to fully get it.
It would look like this if you just converted the arrow function to a function function:
sortedArticles(): Article[] {
return this.articles.sort(function(a: Article, b: Article) { return b.votes - a.votes;});
// ---------------------------^^^^^^^^------------------------^^^-------------------------^^
}
...but note that there's more going on there than ES2015 ("ES6"). The : Article[] part is saying that sortedArticles returns an array of Article. (And similarly the : Article qualifiers on a and b.) That's not JavaScript at all. It looks like TypeScript.
The pure JavaScript version would just drop those type annotations:
sortedArticles() {
return this.articles.sort(function(a, b) { return b.votes - a.votes;});
}
But TypeScript's "fat arrow" functions work largely the same way ES2015's arrow functions do, so let's continue on the basis that we're talking about ES2015 arrow functions:
There are four fundamental differences1 between arrow functions and function functions:
They close over this, super, and several other things,2 they don't have their own versions of those like function functions do. (A consequence of this is that they can use super if they're defined in a context that can use super, which function functions cannot.)
They can have a concise body rather than a verbose one (but they can have a verbose body as well).
They cannot be used as constructors. E.g., you can't use new with an arrow function. A consequence of this is that arrow functions don't have a prototype property on them (since it's only used if the function is used with new).
There is no generator syntax for arrow functions. E.g., there is no arrow equivalent to function *foo() { ... }.
These three functions are all effectively the same, since they don't use this or arguments:
// A `function` function
var f1 = function(x) {
return x * 2;
};
// An arrow function with a verbose body
var f2 = x => {
return x * 2;
};
// An arrow function with a concise body
var f3 = x => x * 2;
(If they used this or arguments, they would not be the same.)
Note that the concise body doesn't have a { after the => and must contain a single top-level expression (which can of course have subexpressions), which is used as the return value.
1 You'll find people telling you there's a fifth: That arrow functions cannot have a name. That's a myth. Arrow functions can have names; the arrow functions above have true names, f2 and f3 respectively. It's not just the variables that have names, the functions do as well.
2 Specifically, they close over this, super, arguments (the automatic pseudo-array of runtime arguments), and new.target.
A huge thank you to CodingIntrigue for pointing out several errors and omissions in the earlier versions of this answer.
If you're not familiar with arrow function, or if it's complicated, you can use JS Refactor, it's a Visual Studio Code extension. It can convert arrow function to normal function. Hope it helps someone.
Related
Es6, Classes there. We have the method (go) like this :
the example in ES6
class X{
go(){}
}
var y = new X();
var z = new y.go();
console.log(z)
Example of the Error Screen Shot:
We don't have property prototype of this method (go), so we can't create new Object from this method. This is the fact. But I can't understand WHY?
Why the developers of javascript in ES6 don't let me use this functionality.
Vice versa in ES5 we can create new instance from Object's methods. Of course, it works from prototype's methods too
the example in Es5
function X (){}
X.prototype.go = function(){}
var y = new X();
var z = new y.go();
console.log(z)
But I can't understand WHY?
ES2015 distinguishes between two types of functions:
callable functions: functions that can be called without new, i.e. foo().
constructable functions: functions that can be called with new.
Whether a function is callable or constructable or both depends on how it is defined. The specification simply dictates that functions declared via the method syntax are not constructable.
Now, that doesn't explain the reasons behind this decision. I can't speak for the TC39 committee, but a clear effort with ES2015 was to reduce some of the surprising behaviors around functions. As such it was enforced how certain types of functions can be used. A method is conceptually not a constructor and thus you cannot call it as such.
Constructable functions:
Classes
Callable functions:
Arrow functions
Object/class methods (via method syntax)
Generator functions
Async functions
Both:
Function declarations/expressions
This question already has answers here:
Are 'Arrow Functions' and 'Functions' equivalent / interchangeable?
(4 answers)
Closed 6 years ago.
I am curious about ES6 arrow functions (fat arrow functions). Are they simply syntactic sugar derived from CoffeeScript, or is there more to them than meets the eye?
ES6 Arrow functions in depth
One of the prettiest features of ES6, it could easily win a beauty contest, if such a contest would be held. What many people don’t know is that the arrow function is not simply a form of syntactic sugar that we can use instead of the regular callback.
As I like to explain it to the people who attend my trainings/workshops, arrow functions are this-less, arguments-less, new.target-less and super-less.
Let us now get past the shorter syntax and dive deeper into the specifics of the arrow function.
Lexical-bound this
Previously, regular functions would have their this value set to the global object if they were used as callbacks, to a new object in case they were called with the new operator or, in the case of libraries like jQuery, they would be set to the object that triggered an event in case of event handlers, or the current element in a $.each iteration.This situation proved very confusing even for experienced developers.
Let’s say you have a piece of code like the one below.
var obj = {
nameValue: 'default',
initializeHandlers: function() {
var nameInput = document.querySelector('#name');
nameInput.addEventListener('blur', function(event) {
this.nameValue = event.target.value;
});
}
};
obj.initializeHandlers();
The problem is that this inside the blur event handler is set to the global object rather than obj. In strict mode — ‘use strict’; — you risk breaking your application because this is set to undefined. In order to side-step this issue we have two options:
Convert the event handler to a function bound to the outer scope, using Function.prototype.bind
Use the dirty var self = this; expression in the initializeHandlers function (I see this as a hack)
Both options are illustrated below.
[...]
initializeHandlers: function() {
var nameInput = document.querySelector('#name');
// more elegant but we can do better
var blurHandler = function(event) {
this.nameValue = event.target.value;
}.bind(this)
nameInput.addEventListener('blur', blurHandler);
}
[...]
[...]
initializeHandlers: function() {
var nameInput = document.querySelector('#name');
// ugly and error-prone
var self = this;
nameInput.addEventListener('blur', function(event) {
self.nameValue = event.target.value;
});
}
[...]
On the other hand, arrow functions have no internal context. They inherit their context from the outer scope. Let’s take a look at how arrow functions solve this problem.
const obj = {
nameValue: 'default',
initializeHandlers: function() {
const nameInput = document.querySelector('#name');
nameInput.addEventListener('blur', (event) => {
// this references obj instead of the global object
this.nameValue = event.target.value;
});
}
};
In our new implementation this is a hard reference to the obj object and doesn’t get lost due to nesting.
Lexical arguments
Have you ever tried to access the arguments object inside an arrow function? I have, and I wasted 3 solid hours trying to figure out why do I get the arguments of the outer function instead of those of the arrow functions.
Thankfully, MDN exists, and as good practice dictates, you check the documentation at the end, when you sit in a corner, knees tucked to your chest, rocking and repeating to yourself: “I should have been a carpenter!”
Fun aside, arrow functions do not expose an arguments object. If you try to access it, you will get the arguments of the surrounding function. In our case, given the fact that the outer function is an arrow function as well, and we have no more functions further up the chain, we will get a ReferenceError.
const variadicAdder = (x) => {
return () => {
let args = Array.prototype.slice.call(arguments, 0);
return args.reduce((accumulator, current) => {
return accumulator + current;
}, x);
}
}
const variadicAdderOf5 = variadicAdder(5);
console.log(variadicAdderOf5(10, 11, 12));
// ReferenceError: arguments is not defined
There is no fix here, as there is nothing broken. What we can do is to return a plain function, rather than an arrow, from our variadicAdder().
This will give us the opportunity to access the arguments object without an issue. The updated code will look like the one below with the only difference
that it will actually work and not throw an error.
const variadicAdder = (x) => {
return function() {
let args = Array.prototype.slice.call(arguments, 0);
return args.reduce((accumulator, current) => {
return accumulator + current;
}, x);
}
}
const variadicAdderOf5 = variadicAdder(5);
console.log(variadicAdderOf5(10, 11, 12));
// 38
To find out more about Array.prototype.reduce, head to the Mozilla Developer Network.
Other characteristics
As I mentioned in the introductory section of this article, arrow functions have several more characteristics besides the context and the arguments.
The first thing I would like to mention is that you are unable to use the new operator with arrow functions. As a direct implication, arrow functions also don’t have super(). Snippets like the one below would simply throw a TypeError.
const Person = (name) => {
this.name = name;
};
let p = new Person('John');
// TypeError: Person is not a constructor
The third characteristic, which is as well, a direct implication of the inability to use the new operator, is the fact that arrow functions don’t have new.target. In a nutshell, new.target allows you to detect whether or not a function has been called as a constructor.
Arrow functions, inherit new.target from their surrounding scope. If the outer scope is a function, and it is called like a constructor (e.g. new Person('Adrian');), then new.target will point to the outer function.
The Mozilla Developer Network hosts a detailed explanation on new.target and I encourage you to check it out.
This article is also published on my blog, here: /es6-arrow-functions-in-depth/
That is, how do I express
function *(next) {}
with arrow syntax? I've tried all the combinations I could think of, and I can't find any documentation on it.
(I am currently using Node.js v0.11.14.)
Can I use ES6's arrow function syntax with generators?
You can't. Sorry.
According to MDN
The function* statement (function keyword followed by an asterisk) defines a generator function.
From a spec document (my emphasis):
The function syntax is extended to add an optional * token:
FunctionDeclaration: "function" "*"? Identifier "(" FormalParameterList? ")"
"{" FunctionBody "}"
The difference between Inline-functions and Arrow-functions
First of all Arrow-functions () => {} are not made to replace Inline-functions function(){} and they are different.
Inline-Functions are simply Functions, so the question is what the difference between Arrow-functions and Inline-Functions are.
An arrow function expression (also known as arrow function) has a shorter syntax compared to function expressions and does not bind its own this, arguments, super, or new.target). Arrow functions are always anonymous.
Some more quick details here
Why Arrow-function can not be used as generators
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Use of the yield keyword
The yield keyword may not be used in an arrow function's body (except when permitted within functions further nested within it). As a consequence, arrow functions cannot be used as generators.
Note that generators without yield don't make sense.
Why Arrow-function can not use yield
http://tc39wiki.calculist.org/es6/arrow-functions/
Arrow functions bind this lexically, bind return in the Block body case so it returns from the immediately enclosing arrow function, and preclude break and continue from referencing statements outside the immediately enclosing arrow function.
The Identifier primary expression arguments may not be used in an arrow function's body (whether expression or block form).
Likewise, yield may not be used in an arrow function's body. Arrows cannot be generators and we do not want deep continuations.
Yield in an Arrow-Function will throw Semantic Error: http://www.ecma-international.org/
In the End the reason is in the deep complexity in the implementation of ECMA6. C# does not allow this as well for somewhat similar reasons.
In addition to the discussion on esdiscuss.org and the Ecma TC39 committee ES6 meeting notes from November 2013 mentioned above, generator arrows were revisited in two September 2016 ES7 meetings [1] [2]. After a discussion about pros and cons of various syntax (mainly =*> and =>*) and a lack of justifications and use cases for this feature, they came to the conclusion that:
There is some interest from the committee, but concern that the feature does not pull its weight for adding a new piece of syntax
Plan to revisit on Day 3 to see if we can get =>* to stage 0 at least, as part of [Domenic Denicola]'s async iteration proposal
The proposal for generator arrows was moved to Stage 1 with Brendan Eich and Domenic Denicola as champions. Asynchronous iteration mentioned above was finished and implemented in 2018.
In Oct 2019 an official repo by Sergey Rubanov appeared with more discussion about syntax and other details.
I was also having the same question and came here. After reading the posts and comments, I felt using generator in an arrow function seems to be vague:
const generator = () => 2*3; // * implies multiplication
// so, this would be a confusing
const generator = () =>* something; // err, multiplying?
const generator = () =*> ... // err, ^^
const generator = ()*=> ... // err, *=3, still multiplying?
const generator=*()=> ... // err, ^^
const generator = *param => ... //err, "param" is not fixed word
This is what may be the big reason they didn't implement generator in relation with arrow function.
But, if I were one of them, I could have thought like this:
const generator = gen param => ... // hmm, gen indicates a generator
const generator = gen () => ... // ^^
This feels just like we have asynchronous function:
const asyncFunction = async () => ... // pretty cool
Because, with normal function the async keyword exist, so arrow function is utilizing it - async () => is likely to seem async function().
But, there's no keyword like gen or generator and alas arrow function is not using it.
To conclude:
Even if they wish to implement the generator in the arrow function, I think they need to re-think about generator syntax in core js:
generator function myfunc() {}
// rather than
function* myfunc() {} // or, function *myfunc() {}
And this will be a big blunder. So, keeping arrow function out from the generator, is pretty cool.
Following #Bergi comment:
No. Arrow functions are supposed to be light-weight (and don't have a .prototype for example) and often one-liners, while generators are pretty much the opposite.
I will say that generator purpose to use is run-stop-run and so I don't think we need to care about prototype, lexical this, etc.
Right now you can not, but in future you might be because TC39 release proposal for same in october 2019, which is in stage 1.
I know that this is very late, but another possible reason could be syntax. maybe (*() => {}) works, but what about (9 ** () => {})? Is that 9 to the power of an arrow function, returning NaN, or is it 9 times a generator arrow function, also returning NaN? It could be done with some alternative syntax, like =>* as mentioned by another answer here, but maybe there was a desire to preserve the consistency of the generator function syntax (eg. function* () {} and { *genMethod() {} }) when it was being implemented. Not too much of an excuse, but a reason for it.
You can, but not really in a nice way. It's not shorter and does not look that pretty. Check this out:
function* iterable(arg) {
yield* [];
}
async function* asyncIterable(arg) {
yield* [];
}
const arrowIterable = arg => {
return {
*[Symbol.iterator]() {
yield* [];
},
};
};
const arrowAsyncIterable = arg => {
return {
async *[Symbol.asyncIterator]() {
yield* [];
},
};
};
This works because an iterable is basically an object with the Symbol.iterator or Symbol.asyncIterator set to an iterator. A generator is an iterator!
Enjoy!
There is a nice workaround with redux-saga
import { call, all } from 'redux-saga/effects';
function* gen() {
yield all([].map(() => {
return call(....);
}));
}
It seems to me that, in ES6, the following two functions are very nearly identical:
function () {
return this;
}.bind(this);
() => {
return this;
};
The end result seems the same: arrow functions produce a JavaScript function object with their this context bound to the same value as the this where they are created.
Obviously, in the general sense, Function.prototype.bind is more flexible than arrow functions: it can bind to values other than the local this, and it can bind any function's this at any point in time, potentially long after it is initially created. However, I'm not asking how bind itself is different from arrow functions, I'm asking how arrow functions differ from immediately calling bind with this.
Are there any differences between the two constructs in ES6?
There are no (significant) differences.
Well, okay, that's a little premature. There are three tiny differences unique to arrow functions.
Arrow functions cannot be used with new.
This means, of course, that they do not have a prototype property and cannot be used to create an object with the classically-inspired syntax.
new (() => {}) // TypeError: () => {} is not a constructor
This is probably for the best, though—the way new works would not make much sense with bound functions.
Arrow functions do not have access to the special arguments object that ordinary JavaScript functions have access to.
(() => arguments)(1, 2, 3) // ReferenceError: arguments is not defined
This one is probably a little bit more of a gotcha. Presumably this is to remove one of JavaScript's other oddities. The arguments object is its own special beast, and it has strange behavior, so it's not surprising that it was tossed.
Instead, ES6 has splats that can accomplish the same thing without any magic hidden variables:
((...args) => args)(1, 2, 3) // [1, 2, 3]
Arrow functions do not have their own new.target property, they use the new.target of their enclosing function, if it exists.
This is consistent with the other changes to remove "magically" introduced values for arrow functions. This particular change is especially obvious, considering arrow functions can't be used with new anyway, as mentioned above.
Otherwise, arrows are just like bound functions, semantically. It's possible for arrows to be more performant, since they don't have to carry around the extra baggage and since they don't need to be converted from ordinary functions first, but they're behaviorally exactly the same.
There are a few differences:
Arrow functions cannot be constructed. While both arrow functions and bound functions both don't have a .prototype property, the former do throw an exception when called with new while the latter just ignore the bound value and call their target function as a constructor (with the partially applied bound arguments, though) on the new instance.
function F() {}
var f = () => {},
boundF = F.bind({});
console.log(new boundF(), new boundF instanceof F) // {}, true
console.log(new f) // TypeError
Arrow functions do have lexical arguments, new.target and super as well (not only lexical this). A call to an arrow function does not initialise any of those, they are just inherited from the function the arrow function was defined in. In a bound function, they just refer to the respective values of the target function.
Arrow functions don't actually bind a this value. Rather, they don't have one, and when you use this it is looked up like a variable name in the lexical scope. This does allow you to lazily define an arrow function while this is not yet available:
class X extends Object {
constructor() {
var f = () => this, // works
boundF = function(){ return this; }.bind(this);
// ^^^^ ReferenceError
super(); // initialises `this`
console.log(f(), f() == this); // {}, true
}
}
new X;
Arrow functions cannot be generator functions (though they can return generators). You can use .bind() on a generator function, yet there is no way to express this using an arrow function.
Here is one more subtle difference:
Arrow functions can return a value without using the 'return' keyword, by omitting the {} braces following the => immediately.
var f=x=>x; console.log(f(3)); // 3
var g=x=>{x}; console.log(g(3)); // undefined
var h=function(x){x}; console.log(h(3)); // undefined
var i=x=>{a:1}; console.log(i(3)); // undefined
var j=x=>({a:1}); console.log(j(3)); // {a:1}
That is, how do I express
function *(next) {}
with arrow syntax? I've tried all the combinations I could think of, and I can't find any documentation on it.
(I am currently using Node.js v0.11.14.)
Can I use ES6's arrow function syntax with generators?
You can't. Sorry.
According to MDN
The function* statement (function keyword followed by an asterisk) defines a generator function.
From a spec document (my emphasis):
The function syntax is extended to add an optional * token:
FunctionDeclaration: "function" "*"? Identifier "(" FormalParameterList? ")"
"{" FunctionBody "}"
The difference between Inline-functions and Arrow-functions
First of all Arrow-functions () => {} are not made to replace Inline-functions function(){} and they are different.
Inline-Functions are simply Functions, so the question is what the difference between Arrow-functions and Inline-Functions are.
An arrow function expression (also known as arrow function) has a shorter syntax compared to function expressions and does not bind its own this, arguments, super, or new.target). Arrow functions are always anonymous.
Some more quick details here
Why Arrow-function can not be used as generators
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Use of the yield keyword
The yield keyword may not be used in an arrow function's body (except when permitted within functions further nested within it). As a consequence, arrow functions cannot be used as generators.
Note that generators without yield don't make sense.
Why Arrow-function can not use yield
http://tc39wiki.calculist.org/es6/arrow-functions/
Arrow functions bind this lexically, bind return in the Block body case so it returns from the immediately enclosing arrow function, and preclude break and continue from referencing statements outside the immediately enclosing arrow function.
The Identifier primary expression arguments may not be used in an arrow function's body (whether expression or block form).
Likewise, yield may not be used in an arrow function's body. Arrows cannot be generators and we do not want deep continuations.
Yield in an Arrow-Function will throw Semantic Error: http://www.ecma-international.org/
In the End the reason is in the deep complexity in the implementation of ECMA6. C# does not allow this as well for somewhat similar reasons.
In addition to the discussion on esdiscuss.org and the Ecma TC39 committee ES6 meeting notes from November 2013 mentioned above, generator arrows were revisited in two September 2016 ES7 meetings [1] [2]. After a discussion about pros and cons of various syntax (mainly =*> and =>*) and a lack of justifications and use cases for this feature, they came to the conclusion that:
There is some interest from the committee, but concern that the feature does not pull its weight for adding a new piece of syntax
Plan to revisit on Day 3 to see if we can get =>* to stage 0 at least, as part of [Domenic Denicola]'s async iteration proposal
The proposal for generator arrows was moved to Stage 1 with Brendan Eich and Domenic Denicola as champions. Asynchronous iteration mentioned above was finished and implemented in 2018.
In Oct 2019 an official repo by Sergey Rubanov appeared with more discussion about syntax and other details.
I was also having the same question and came here. After reading the posts and comments, I felt using generator in an arrow function seems to be vague:
const generator = () => 2*3; // * implies multiplication
// so, this would be a confusing
const generator = () =>* something; // err, multiplying?
const generator = () =*> ... // err, ^^
const generator = ()*=> ... // err, *=3, still multiplying?
const generator=*()=> ... // err, ^^
const generator = *param => ... //err, "param" is not fixed word
This is what may be the big reason they didn't implement generator in relation with arrow function.
But, if I were one of them, I could have thought like this:
const generator = gen param => ... // hmm, gen indicates a generator
const generator = gen () => ... // ^^
This feels just like we have asynchronous function:
const asyncFunction = async () => ... // pretty cool
Because, with normal function the async keyword exist, so arrow function is utilizing it - async () => is likely to seem async function().
But, there's no keyword like gen or generator and alas arrow function is not using it.
To conclude:
Even if they wish to implement the generator in the arrow function, I think they need to re-think about generator syntax in core js:
generator function myfunc() {}
// rather than
function* myfunc() {} // or, function *myfunc() {}
And this will be a big blunder. So, keeping arrow function out from the generator, is pretty cool.
Following #Bergi comment:
No. Arrow functions are supposed to be light-weight (and don't have a .prototype for example) and often one-liners, while generators are pretty much the opposite.
I will say that generator purpose to use is run-stop-run and so I don't think we need to care about prototype, lexical this, etc.
Right now you can not, but in future you might be because TC39 release proposal for same in october 2019, which is in stage 1.
I know that this is very late, but another possible reason could be syntax. maybe (*() => {}) works, but what about (9 ** () => {})? Is that 9 to the power of an arrow function, returning NaN, or is it 9 times a generator arrow function, also returning NaN? It could be done with some alternative syntax, like =>* as mentioned by another answer here, but maybe there was a desire to preserve the consistency of the generator function syntax (eg. function* () {} and { *genMethod() {} }) when it was being implemented. Not too much of an excuse, but a reason for it.
You can, but not really in a nice way. It's not shorter and does not look that pretty. Check this out:
function* iterable(arg) {
yield* [];
}
async function* asyncIterable(arg) {
yield* [];
}
const arrowIterable = arg => {
return {
*[Symbol.iterator]() {
yield* [];
},
};
};
const arrowAsyncIterable = arg => {
return {
async *[Symbol.asyncIterator]() {
yield* [];
},
};
};
This works because an iterable is basically an object with the Symbol.iterator or Symbol.asyncIterator set to an iterator. A generator is an iterator!
Enjoy!
There is a nice workaround with redux-saga
import { call, all } from 'redux-saga/effects';
function* gen() {
yield all([].map(() => {
return call(....);
}));
}