[javascript] What do multiple arrow functions mean in javascript?

I have been reading a bunch of react code and I see stuff like this that I don't understand:

handleChange = field => e => {
  e.preventDefault();
  /// Do something here
}

This question is related to javascript ecmascript-6 arrow-functions

The answer is


The example in your question is that of a curried function which makes use of arrow function and has an implicit return for the first argument.

Arrow function lexically bind this i.e they do not have their own this argument but take the this value from the enclosing scope

An equivalent of the above code would be

const handleChange = (field) {
  return function(e) {
     e.preventDefault();
     /// Do something here
  }.bind(this);
}.bind(this);

One more thing to note about your example is that define handleChange as a const or a function. Probably you are using it as part of a class method and it uses a class fields syntax

so instead of binding the outer function directly, you would bind it in the class constructor

class Something{
    constructor(props) {
       super(props);
       this.handleChange = this.handleChange.bind(this);
    }
    handleChange(field) {
        return function(e) {
           e.preventDefault();
           // do something
        }
    }
}

Another thing to note in the example is the difference between implicit and explicit return.

const abc = (field) => field * 2;

Above is an example of implicit return ie. it takes the value field as argument and returns the result field*2 which explicitly specifying the function to return

For an explicit return you would explicitly tell the method to return the value

const abc = () => { return field*2; }

Another thing to note about arrow functions is that they do not have their own arguments but inherit that from the parents scope as well.

For example if you just define an arrow function like

const handleChange = () => {
   console.log(arguments) // would give an error on running since arguments in undefined
}

As an alternative arrow functions provide the rest parameters that you can use

const handleChange = (...args) => {
   console.log(args);
}

That is a curried function

First, examine this function with two parameters …

const add = (x, y) => x + y
add(2, 3) //=> 5

Here it is again in curried form …

const add = x => y => x + y

Here is the same1 code without arrow functions …

const add = function (x) {
  return function (y) {
    return x + y
  }
}

Focus on return

It might help to visualize it another way. We know that arrow functions work like this – let's pay particular attention to the return value.

const f = someParam => returnValue

So our add function returns a function – we can use parentheses for added clarity. The bolded text is the return value of our function add

const add = x => (y => x + y)

In other words add of some number returns a function

add(2) // returns (y => 2 + y)

Calling curried functions

So in order to use our curried function, we have to call it a bit differently …

add(2)(3)  // returns 5

This is because the first (outer) function call returns a second (inner) function. Only after we call the second function do we actually get the result. This is more evident if we separate the calls on two lines …

const add2 = add(2) // returns function(y) { return 2 + y }
add2(3)             // returns 5

Applying our new understanding to your code

related: ”What’s the difference between binding, partial application, and currying?”

OK, now that we understand how that works, let's look at your code

handleChange = field => e => {
  e.preventDefault()
  /// Do something here
}

We'll start by representing it without using arrow functions …

handleChange = function(field) {
  return function(e) {
    e.preventDefault()
    // Do something here
    // return ...
  };
};

However, because arrow functions lexically bind this, it would actually look more like this …

handleChange = function(field) {
  return function(e) {
    e.preventDefault()
    // Do something here
    // return ...
  }.bind(this)
}.bind(this)

Maybe now we can see what this is doing more clearly. The handleChange function is creating a function for a specified field. This is a handy React technique because you're required to setup your own listeners on each input in order to update your applications state. By using the handleChange function, we can eliminate all the duplicated code that would result in setting up change listeners for each field. Cool!

1 Here I did not have to lexically bind this because the original add function does not use any context, so it is not important to preserve it in this case.


Even more arrows

More than two arrow functions can be sequenced, if necessary -

const three = a => b => c =>
  a + b + c

const four = a => b => c => d =>
  a + b + c + d

three (1) (2) (3) // 6

four (1) (2) (3) (4) // 10

Curried functions are capable of surprising things. Below we see $ defined as a curried function with two parameters, yet at the call site, it appears as though we can supply any number of arguments. Currying is the abstraction of arity -

_x000D_
_x000D_
const $ = x => k =>_x000D_
  $ (k (x))_x000D_
  _x000D_
const add = x => y =>_x000D_
  x + y_x000D_
_x000D_
const mult = x => y =>_x000D_
  x * y_x000D_
  _x000D_
$ (1)           // 1_x000D_
  (add (2))     // + 2 = 3_x000D_
  (mult (6))    // * 6 = 18_x000D_
  (console.log) // 18_x000D_
  _x000D_
$ (7)            // 7_x000D_
  (add (1))      // + 1 = 8_x000D_
  (mult (8))     // * 8 = 64_x000D_
  (mult (2))     // * 2 = 128_x000D_
  (mult (2))     // * 2 = 256_x000D_
  (console.log)  // 256
_x000D_
_x000D_
_x000D_

Partial application

Partial application is a related concept. It allows us to partially apply functions, similar to currying, except the function does not have to be defined in curried form -

const partial = (f, ...a) => (...b) =>
  f (...a, ...b)

const add3 = (x, y, z) =>
  x + y + z

partial (add3) (1, 2, 3)   // 6

partial (add3, 1) (2, 3)   // 6

partial (add3, 1, 2) (3)   // 6

partial (add3, 1, 2, 3) () // 6

partial (add3, 1, 1, 1, 1) (1, 1, 1, 1, 1) // 3

Here's a working demo of partial you can play with in your own browser -

_x000D_
_x000D_
const partial = (f, ...a) => (...b) =>_x000D_
  f (...a, ...b)_x000D_
  _x000D_
const preventDefault = (f, event) =>_x000D_
  ( event .preventDefault ()_x000D_
  , f (event)_x000D_
  )_x000D_
  _x000D_
const logKeypress = event =>_x000D_
  console .log (event.which)_x000D_
  _x000D_
document_x000D_
  .querySelector ('input[name=foo]')_x000D_
  .addEventListener ('keydown', partial (preventDefault, logKeypress))
_x000D_
<input name="foo" placeholder="type here to see ascii codes" size="50">
_x000D_
_x000D_
_x000D_


Brief and simple

It is a function which returns another function written in short way.

const handleChange = field => e => {
  e.preventDefault()
  // Do something here
}

// is equal to 
function handleChange(field) {
  return function(e) {
    e.preventDefault()
    // Do something here
  }
}

Why people do it ?

Have you faced when you need to write a function which can be customized? Or you have to write a callback function which has fixed parameters (arguments), but you need to pass more variables to the function but avoiding global variables? If your answer "yes" then it is the way how to do it.

For example we have a button with onClick callback. And we need to pass id to the function, but onClick accepts only one parameter event, we can not pass extra parameters within like this:

const handleClick = (event, id) {
  event.preventDefault()
  // Dispatch some delete action by passing record id
}

It will not work!

Therefore we make a function which will return other function with its own scope of variables without any global variables, because global variables are evil .

Below the function handleClick(props.id)} will be called and return a function and it will have id in its scope! No matter how many times it will be pressed the ids will not effect or change each other, they are totally isolated.

const handleClick = id => event {
  event.preventDefault()
  // Dispatch some delete action by passing record id
}

const Confirm = props => (
  <div>
    <h1>Are you sure to delete?</h1>
    <button onClick={handleClick(props.id)}>
      Delete
    </button>
  </div
)

Other benefit

A function which returns another function also called "curried functions" and they are used for function compositions.

You can find example here: https://gist.github.com/sultan99/13ef56b4089789a8d115869ee2c5ec47


Understanding the available syntaxes of arrow functions will give you an understanding of what behaviour they are introducing when 'chained' like in the examples you provided.

When an arrow function is written without block braces, with or without multiple parameters, the expression that constitutes the function's body is implicitly returned. In your example, that expression is another arrow function.

No arrow funcs              Implicitly return `e=>{…}`    Explicitly return `e=>{…}` 
---------------------------------------------------------------------------------
function (field) {         |  field => e => {            |  field => {
  return function (e) {    |                             |    return e => {
      e.preventDefault()   |    e.preventDefault()       |      e.preventDefault()
  }                        |                             |    }
}                          |  }                          |  }

Another advantage of writing anonymous functions using the arrow syntax is that they are bound lexically to the scope in which they are defined. From 'Arrow functions' on MDN:

An arrow function expression has a shorter syntax compared to function expressions and lexically binds the this value. Arrow functions are always anonymous.

This is particularly pertinent in your example considering that it is taken from a application. As as pointed out by @naomik, in React you often access a component's member functions using this. For example:

Unbound                     Explicitly bound            Implicitly bound 
------------------------------------------------------------------------------
function (field) {         |  function (field) {       |  field => e => {
  return function (e) {    |    return function (e) {  |    
      this.setState(...)   |      this.setState(...)   |    this.setState(...)
  }                        |    }.bind(this)           |    
}                          |  }.bind(this)             |  }

A general tip , if you get confused by any of new JS syntax and how it will compile , you can check babel. For example copying your code in babel and selecting the es2015 preset will give an output like this

handleChange = function handleChange(field) {
 return function (e) {
 e.preventDefault();
  // Do something here
   };
 };

babel


It might be not totally related, but since the question mentioned react uses case (and I keep bumping into this SO thread): There is one important aspect of the double arrow function which is not explicitly mentioned here. Only the 'first' arrow(function) gets named (and thus 'distinguishable' by the run-time), any following arrows are anonymous and from React point of view count as a 'new' object on every render.

Thus double arrow function will cause any PureComponent to rerender all the time.

Example

You have a parent component with a change handler as:

handleChange = task => event => { ... operations which uses both task and event... };

and with a render like:

{ tasks.map(task => <MyTask handleChange={this.handleChange(task)}/> }

handleChange then used on an input or click. And this all works and looks very nice. BUT it means that any change that will cause the parent to rerender (like a completely unrelated state change) will also re-render ALL of your MyTask as well even though they are PureComponents.

This can be alleviated many ways such as passing the 'outmost' arrow and the object you would feed it with or writing a custom shouldUpdate function or going back to basics such as writing named functions (and binding the this manually...)


Think of it like this, every time you see a arrow, you replace it with function.
function parameters are defined before the arrow.
So in your example:

field => // function(field){}
e => { e.preventDefault(); } // function(e){e.preventDefault();}

and then together:

function (field) { 
    return function (e) { 
        e.preventDefault(); 
    };
}

From the docs:

// Basic syntax:
(param1, param2, paramN) => { statements }
(param1, param2, paramN) => expression
   // equivalent to:  => { return expression; }

// Parentheses are optional when there's only one argument:
singleParam => { statements }
singleParam => expression