ES6 - deep understanding of arrow function

Posted by hesyar on Thu, 24 Feb 2022 14:32:23 +0100

Arrow function, basic knowledge

There is another very simple syntax for creating functions, and this method is usually better than function expressions.

It is called the "arrow function" because it looks like this:

let func = (arg1, arg2, ..., argN) => expression;

Here, a function func is created, which accepts the parameter arg1 Argn, then use the parameter to evaluate the expression on the right and return its result.

In other words, it is a shorter version of the following code:

let func = function(arg1, arg2, ..., argN) {
  return expression;
};

Let's take a concrete example:

let sum = (a, b) => a + b;

/* This arrow function is a shorter version of the following function:

let sum = function(a, b) {
  return a + b;
};
*/

alert( sum(1, 2) ); // 3

You can see that (a, b) = > a + b means that a function accepts two parameters named a and B. When executed, it evaluates the expression a + b and returns the result.

  • If we only have one parameter, we can also omit the parentheses outside the parameter to make the code shorter.

    For example:

    let double = n => n * 2;
    // Almost equivalent to: let double = function (n) {return n * 2}
    
    alert( double(3) ); // 6
    
  • If there are no parameters, the brackets will be empty (but the brackets should be left):

    let sayHi = () => alert("Hello!");
    
    sayHi();
    

Arrow functions can be used like function expressions.

For example, create a function dynamically:

let age = prompt("What is your age?", 18);

let welcome = (age < 18) ?
  () => alert('Hello') :
  () => alert("Greetings!");

welcome();

At first, the arrow function may not seem familiar or easy to read, but once we get used to it, this situation will soon change.

The arrow function is very convenient for simple single line action s, especially when we are too lazy to type too many words.

Multiline arrow function

The above example takes the parameter from the left side of = >, and then uses the parameter to calculate the value of the expression on the right.

But sometimes we need something more complex, such as multi line expressions or statements. This can also be done, but we should enclose it in curly brackets. Then use an ordinary return to return the value to be returned.

Like this:

let sum = (a, b) => {  // Curly braces indicate the beginning of a multiline function
  let result = a + b;
  return result; // If we use curly braces, we need an explicit "return"
};

alert( sum(1, 2) ); // 3

summary

The arrow function is quite convenient for a function with one line of code. It has two specific types:

  1. Without curly braces: (... Args) = > expression - on the right is an expression: the function evaluates the expression and returns its result.
  2. Curly braces: (... Args) = > {body} - curly braces allow us to write multiple statements in a function, but we need to explicitly return to return something.

Deep understanding of arrow functions

Let's take a closer look at arrow functions.

Arrow functions are more than just "shortcuts" to writing concise code. It also has very special and useful features.

JavaScript is full of situations where we need to write small functions that execute elsewhere.

For example:

  • arr.forEach(func) -- forEach executes func for each array element.
  • setTimeout(func) -- func is executed by the built-in scheduler.
  • ... more.

The essence of JavaScript is to create a function and pass it somewhere.

In such functions, we usually don't want to leave the current context. This is the main battlefield of arrow function.

Arrow function does not have 'this'

The arrow function does not have this. If you access this, it will be obtained from the outside.

For example, we can use it to iterate inside the object method:

let group = {
  title: "Our Group",
  students: ["John", "Pete", "Alice"],

  showList() {
    this.students.forEach(
      student => alert(this.title + ': ' + student)
    );
  }
};

group.showList();

Here, the arrow function is used in forEach, so this The title is exactly the same as the external method showList. That is: group title.

If we use normal functions, an error will occur:

let group = {
  title: "Our Group",
  students: ["John", "Pete", "Alice"],

  showList() {
    this.students.forEach(function(student) {
      // Error: Cannot read property 'title' of undefined
      alert(this.title + ': ' + student);
    });
  }
};

group.showList();

The error is reported because forEach runs the function in it, but the default value of this function is this=undefined, so there is an attempt to access undefined Title.

But arrow functions are fine because they don't have this.

Cannot perform new operation on arrow function

Not having this naturally means another limitation: arrow functions cannot be used as constructor s. They cannot be called with new.

Arrow function VS bind

Arrow function = > and use There are slight differences between the regular functions called by bind(this):

  • . bind(this) creates a "bound version" of the function.
  • Arrow function = > no binding created. The arrow function just doesn't have this. The search method of this is exactly the same as that of conventional variables: find in the external lexical environment.

The arrow function does not have 'arguments'

The arrow function also has no arguments variable.

This is useful for decorators when we need to forward a call using the current this and arguments.

For example, defer(f, ms) gets a function and returns a wrapper that delays the call by ms:

function defer(f, ms) {
  return function() {
      //  this and arguments here are obtained by the function of return
    setTimeout(() => f.apply(this, arguments), ms);
  };
}

function sayHi(who) {
  alert('Hello, ' + who);
}

let sayHiDeferred = defer(sayHi, 2000);
sayHiDeferred("John"); // After 2 seconds: Hello, John

If the arrow function is not used, it can be written as follows:

function defer(f, ms) {
  return function(...args) {
    let ctx = this;
    setTimeout(function() {
        //  If ctx is not used to save this in function, this in setTimeout will be window instead of this in external function
        //  If you do not accept parameters in the external function and apply passed into the internal function, it is also undefined to accept them directly with arguments
      return f.apply(ctx, args);
    }, ms);
  };
}

//  Error example
function defer(f, ms) {
  return function() {
		console.log(arguments);  //  "John"
    setTimeout(function() {
			console.log(arguments); //   undefined
			f.apply(this, arguments)
		}, ms);
  };
}

Here, we must create additional variables args and ctx so that the functions inside setTimeout can get them.

summary

Arrow function:

  • No this
  • No arguments
  • Cannot call with new
  • They also don't have super, but we haven't learned it yet.

This is because the arrow function is for short code that does not have its own "context" but works in the current context. And the arrow function does shine in this use scenario.

Topics: Javascript ECMAScript