One of the most anticipated features in modern JS is the arrow function, identified by =>. The arrow function has two main advantages:
- Shorter functions;
- Because of these advantages, arrow functions are preferred over other forms of function declarations. Like, popular
airbnb eslint configuration
Libraries enforce usageJavaScript
The arrow function creates an anonymous function. However, arrow functions have advantages and some “disadvantages”. This requires some tradeoffs in use. The following from why to use, how to use, when to use, this three parts to make some summary.
Why use?
The introduction of arrow functions serves two purposes: they are shorter functions and do not bind this
Shorter function
var elements = ['h1'.'div'.'span'.'section'];
elements.map(function(el) {
return el.length; // Return array: [2, 3, 4, 7]
});
// From the above ordinary function can be rewritten to the following arrow function
elements.map((el) = > {
return el.length; // [2, 3, 4, 7]
});
// If the arrow function has only one argument, omit the parentheses for the argument
elements.map(el= > {
return el.length; // [2, 3, 4, 7]
});
// When the arrow function body has only one 'return' statement, you can omit the 'return' keyword and the curly braces of the method body
elements.map(el= > el.length); // [2, 3, 4, 7]
// In this example, since we only need the 'length' attribute, we can use the parameter structure
// Note that the string 'length' is the name of the attribute we want to obtain, while 'elLength' is just a variable name that can be replaced with any valid variable name
elements.map(({ "length": elLength }) = > elLength); // [2, 3, 4, 7]
Copy the code
This is not binding
Before the arrow function, each newly defined function has its own this value (a new object in the case of a constructor, undefined in strictly modal function calls, the underlying object if the function is called as an “object method”, etc.). The arrow function does not run up or down on its own, which in effect means that both this and arguments in the code inherit from its parent function.
const obj = {
name: 'test object'.createAnonFunction: function() {
return function() {
console.log(this.name);
return this; }},createArrowFunction: function() {
return (a)= > {
console.log(this.name);
return this; }}}const anon = obj.createAnonFunction();
anon(); // undefined
anon() === window // true
const arrow = obj.createArrowFunction();
arrow(); // 'test object'
arrow() === obj // true
Copy the code
The first anonymous parameter has its own context (pointing to something other than an obj object), and when it is assigned to anon and called, this changes to point to window. Another, the arrow function has the same context as the function that created it and points to the obj object.
Call through call or apply
Since arrow functions do not have their own this pointer, when a function is called through call() or apply(), only arguments (not this) are passed, and their first argument is ignored.
var adder = {
base: 1.add: function(a) {
var f = v= > v + this.base;
return f(a);
},
addByCall: function(a) {
var f = v= > v + this.base;
var b = {
base: 2
};
return f.call(b, a)
}
}
adder.add(1); / / 2
adder.addByCall(1); / / 2
Copy the code
Do not bind the arguments
Arrow functions do not bind Arguments objects. Thus, arguments in this example simply refers to arguments in a closed scope:
function foo(n) {
var f = (a)= > arguments[0] + n; // Implicitly bind arguments object to foo, arguments[0] is n
return f();
}
foo(1); / / 2
Copy the code
In most cases, using residual arguments is a better choice than using arguments objects.
function foo(arg) {
var f = (. agrs) = > args[0];
return f(arg);
}
foo(1); / / 1
function foo(arg1, arg2) {
var f = (. args) = > args[1];
return f(arg1, arg2);
}
foo(1.2); / / 2
Copy the code
How does it work?
Optimize the code
For example, if you have an array with values and you want to map through each item, the arrow function is recommended:
const words = ['hello'.'WORLD'.'Whatever'];
const downcasedWords = words.map(word= > word.toLowerCase());
Copy the code
An extremely common example is to return a value of an object:
const names = objects.map(object= > object.name);
Copy the code
Similarly, when replacing the traditional for loop with forEach, the arrow function actually intuitively keeps this from the parent level:
this.examples.forEach(example= > {
this.runExample(example);
});
Copy the code
Promise and Promise chain
Arrow functions also make code more intuitive and concise when writing asynchronous programming. This is an ideal place for arrow functions, especially if you are generating a function that is stateful and you want to reference something in an object.
this.doSomethingAsync().then((result) = > {
this.storeResult(result);
});
Copy the code
Object conversion
Another common and very useful use of arrow functions is object conversion for encapsulation. In vue.js, for example, there is a common pattern to include parts of the Vuex store directly into the Vue component using mapState. This involves defining a set of Mappers that are used to go from the original object to the full transformation output, which is really necessary in component problems. For this simple series of transformations, the arrow function is the most appropriate. Such as:
export default {
computed: {
...mapState([
'results'.'users'])}}Copy the code
When to use? (Not recommended)
Use the new operator
Arrow functions cannot be used as constructors, and using them with new throws an error.
var Foo = (a)= > {};
var foo = new Foo(); // TypeError: Foo is not a constructor
Copy the code
Using the Prototype attribute
Arrow functions have no prototype attribute.
var Foo = (a)= > {};
console.log(Foo.prototype); // undefined
Copy the code
Use the yield keyword
The yield keyword usually cannot be used in arrow functions (unless nested within an allowed function). Therefore, arrow functions cannot be used as generators.
Deep calls
If you define functions as arrow functions and call them back and forth, you will get confused by the code when debugging bugs, and even get error messages like this:
{anonymous}(){anonymous}(){anonymous}(){anonymous}(){anonymous}() //anonymous
Copy the code
Common mistakes
Returns an object literal
Remember that the simple syntax of params => {object: literal} for returning object literals does not work.
var func = (a)= > { foo: 1 };
func(); // undefined
var func = (a)= > { foo: function() {}};// SyntaxError: function statement requires a name
Copy the code
This is because the code inside curly braces {} is parsed as a series of statements (that is, foo is treated as a tag, not part of an object literal). So remember to enclose object literals in parentheses:
var func = (a)= > ({foo: 1});
Copy the code
A newline
Arrow functions cannot break lines between arguments and arrows.
var func = (a)= > 1;
// SyntaxError: expected expression, got '=>'
Copy the code
Parse order
Although the arrows in arrow functions are not operators, arrow functions have special operator priority resolution rules that are different from regular functions.
let callback;
callback = callback || function() {}; // ok
callback = callback || (a)= > {};
// SyntaxError: invalid arrow-function arguments
callback = callback || (() = > {}); // ok
Copy the code
More examples
Use ternary operators
var foo = a= > a > 15 ? 15 : a;
foo(10); / / 10
foo(16); / / 15
Copy the code
closure
// The standard closure function
function Add() {
var i = 0;
return function() {
return(++i); }}var add = Add();
add(); / / 1
add(); / / 2
// Closure of the body of the arrow function (I = 0 is the default argument)
var Add = (i = 0) = > { return (() = > (++i)) };
var add = Add();
add(); / / 1
add(); / / 2
// Since there is only one return, the return and parentheses can also be omitted
var Add = (i = 0) = > () => (++i);
Copy the code
The arrow function recurses
var fact = (x) = > ( x == 0 ? 1 : x*fact(x- 1)); fact(5); / / 120
Copy the code
conclusion
The arrow function is a very special property of the JS language and makes the code more unpredictable in many cases. However, like other language features, they have their pros and cons. So we should use it only as a tool, not mindlessly simply replace all arrow functions.