📜 ⬆️ ⬇️

Arrow functions in ECMAScript 6

Arrow functions madness
One of the most interesting parts of the new ECMAScript 6 standard is the arrow functions. Arrow functions, as the name implies, are defined by the new syntax that uses the arrow => . However, besides the excellent syntax, the arrow functions differ from the traditional functions in other points:

There were several reasons for introducing these differences. The primary priority is that binding is used quite often in JavaScript. It is very easy to lose this desired value when using traditional functions, which can lead to unpredictable consequences. Another reason is that JS engines can easily optimize the execution of switch functions due to these limitations (as opposed to traditional functions that can be used as a constructor and that are free to modify special variables ).


Note: This article is a compilation of a free translation of the article Understanding ECMAScript 6 arrow functions and readings of the latest draft specification (January 20, 2014 Draft Rev 22).

Table of contents

')

Syntax



In general, the syntax of the switch functions looks like this:

 var fun = (x) => x; 

It is very similar to similar syntax in languages ​​such as Scala, CoffeeScript, and the syntax of lambda expressions from C #.

The syntax of the switch functions may be different, depending on how you declare the function. A declaration always starts with a list of arguments, followed by an arrow and the function body. Both the argument list and the function body can have a different form, depending on what you are writing.

One parameter


Declaring a switch function that takes one argument and simply returns it looks very simple:

 var reflect = value => value; //  var reflect = function(value) { return value; } 

When the arrow function has only one argument, it can be declared without parentheses. The body of the function following the arrow may also be without curly brackets and may not contain the keyword return .

Several parameters


But if you want to declare more than one parameter, you must frame the parameter list in parentheses:

 var sum = (num1, num2) => num1 + num2; //  var sum = function(num1, num2) { return num1 + num2; }; 

The sum function simply sums two arguments. The only difference from the previous example is the presence of parentheses and a comma (just like in traditional functions).

No parameters


Similarly, a function without any arguments must have an empty parameter list enclosed in parentheses:

 var sum = () => 1 + 2; //  var sum = function() { return 1 + 2; }; 


Traditional function body syntax


You can use the syntax of traditional functions for the body of the arrow function when it contains more than one expression. That is, wrap the function in braces and add the return keyword:

 var sum = (num1, num2) => { return num1 + num2; } //  var sum = function(num1, num2) { return num1 + num2; }; 

The body of the function will be processed in the same way as in the case of classical functions, except that the values ​​of the special variables this , super and arguments will be calculated differently.

Object literal


Separately, it should be mentioned that the body of the function which does not contain curly brackets and simply returns the object literal must be put into parentheses:

 var getTempItem = id => ({ id: id, name: "Temp" }); //  var getTempItem = function(id) { return { id: id, name: "Temp" } }; 

Placing a literal object in parentheses indicates to the parser that curly braces are not the beginning of the traditional syntax for the function body, but the beginning of a literal.

Variable number of parameters


Since the “own” object of arguments is not available inside the switch function (the value of arguments is lexically related to the value of the arguments of the traditional function within which the switch function was declared), then for switch functions with a variable number of parameters, use the rest pattern from the restructuring patterns . Example:

 var getTempItems = (...rest) => rest; //  var getTempItems = function() { return [].slice.apply(arguments) }; 

Pattern restructuring as parameter


In this article, we are not looking at restructuring patterns — you can read about them in the article Review of ECMAScript 6, the next version of JavaScript , although this information is partially outdated.

As can be seen from the previous example, despite the fact that the switch function has only one argument, it is still necessary to use parentheses when using the destructuring patterns as the only parameter of the function. Examples with other templates :

 var a = ({a}) => a; var b = ([b]) => b; 


Using arrow functions



Context setting


One of the common scripts in JavaScript is setting the correct value of this inside a function (binding). Since the value of this can be changed, then, depending on the context of the execution of the function, it is possible to mistakenly act on one object when you meant a completely different one. Look at the following example:

 var pageHandler = { id: "123456" , init: function() { document.addEventListener("click", function(event) { this.doSomething(event.type); //  }); } , doSomething: function(type) { console.log("Handling " + type + " for " + this.id) } }; 

In the above code, the pageHandler object must handle clicks on the page. The init() method hangs the handler on the desired event, which internally causes this.doSomething() . However, the code will not work properly. The reference to this.doSomething() not valid, since this points to a document object inside an event handler instead of the intended pageHandler . When you try to execute this code, you will get an error, because the document object does not have a doSomething method.

You can set this value on the pageHandler object using handleEvent or by calling the standard bind() method of the function:

 var pageHandler = { id: "123456" , init: function() { document.addEventListener("click", (function(event) { this.doSomething(event.type); // error }).bind(this)); } , doSomething: function(type) { console.log("Handling " + type + " for " + this.id) } }; 

Now the code works as intended, but it looks more cumbersome. In addition, calling bind(this) every time you create a new function, the value of which is tied to the pageHandler value, but the code works as you intended.

Arrow functions solve the problem in a more elegant way because they use the lexical binding of the value of this (as well as super and arguments ) and its value is determined by the value of this in the place where the arrow function was created. For example:

 var pageHandler = { id: "123456" , init: function() { document.addEventListener("click", event => this.doSomething(event.type)); } , doSomething: function(type) { console.log("Handling " + type + " for " + this.id) } }; 

In this example, the handler is a pointer function in which this.doSomething() called. The value of this will be the same as in the function init() , and the code in this example will work correctly, similar to the one used by bind() . Regardless of whether the call to this.doSomething() returns a value or not, the expression inside the body of the switch function does not need to be enclosed in braces.

In addition, the example above is also more efficient than calling bind() , because for the browser it is similar to the following code:

 var pageHandler = { id: "123456" , init: function() { var self = this; document.addEventListener("click", function(event) { return self.doSomething(event.type) }); } , doSomething: function(type) { console.log("Handling " + type + " for " + this.id) } }; 

That is, the creation of a new function does not occur, as is the case with the bind() call.

Prokidyvanie context between multiple calls


Obviously, you can put one switch function into another, thereby “pushing” the value of this through them:

 var obj = { arr1: [1, 2, 3] , arr2: ['a', 'b', 'c'] , concatenate: function(a, b){ return a + "|" + b } , intersection: function() { return this.arr1.reduce( (sum, v1) => // arrow function 1 this.arr2.reduce( (sum, v2) => { // arrow function 2 sum.push( this.concatenate( v1, v2 ) ) return sum; } , sum ) , [] ) } }; var arrSum = obj.intersection();//['1|a', '1|b', '1|c', '2|a', '2|b', '2|c', '3|a', '3|b', '3|c'] 


Use as argument


The short syntax of the switch functions makes them ideal candidates for passing as arguments to a call to other functions. For example, if you want to sort an array, you usually write something like this:

 var result = values.sort(function(a, b) { return a - b }); 

Pretty verbose for a simple operation. Compare with a short recording of the switch function:

 var result = values.sort((a, b) => a - b); 

Using methods such as massive sort() , map() , reduce() and so on can be simplified using the short syntax of the arrow function.

Other features of the switch functions



Although the switch functions are different from the traditional functions, they have common features:

The essential difference from traditional functions is that an attempt to call an arrow function with an indication of the operator new will cause an execution error.

Total



Arrow functions are one of the most interesting innovations in ECMAScript 6, which, having a short definition syntax, will simplify the transfer of functions as a parameter value to another function.

Laconic syntax allows you to write complex things. even harder simpler. For example, the identifier generator will look like this (which looks much more verbose on es5):

 let idGen = (start = 0, id = start, reset = (newId = start) => id = newId, next = () => id++) => ({reset, next}); let gen = idGen(100); console.log(gen.next(), gen.next(), gen.reset(10), gen.next());//100 101 10 10 

A lexical binding will close one of the biggest sources of pain and frustration for developers, as well as improve performance by optimizing at the level of the js-engine.
Madness in FF
If you want to try the arrow functions, you can run the above examples in the Firefox console, which at the moment (02.2014 FF28) almost fully supports the arrow functions (FF28 doesn’t calculate the arguments value correctly).

You can also try the switch functions and other es6 features in the Traceur online translator .

Source: https://habr.com/ru/post/213455/


All Articles