Difficulty in interpreting Arrow functions that return Arrow functions in Javascript

Asked

Viewed 104 times

5

I was seeing Javascript dependency injection and came across the following syntax:

() => () => {}

I know that () => {} is a Arrow Function which, in short, is a different way of creating a function in which it is not necessary to give a name, which in parentheses are the parameters and in the keys is the function code.

But I can’t understand when there are two parentheses:

() => () => {}

Can you explain to me what the first one is for () => in the above example?

An example:

Filing cabinet calcular.js:

const Celular = (carregador) => () => {
    const carregar = (){
        return carregador.enviaEnergia()
    }
    return{
        carregar
    }
}
modules.exports = celular

Another file:

const Celular = require('./celular')
const Carregador = require('./carregador')
const carregador = Carregador(5)
const celular = Celular(carregador)()

I know which charger is some module that will make injection into cellular dependency.

  • can put an example in your question?

2 answers

4


This syntax does not imply dependency injection, it just means one function is returning another. More explicitly, what is occurring is the following:

function Carregar() {
  return function() {

  };
}

However, this type of construction allows you to achieve some goals more easily due to the Javascript closures system. The above pattern also takes the factory function name or Factory Function in English, in which Carregar is the factory. In this case, Carregar is the factory function, which whenever called will create a new function, returning it.

Somehow, this pattern slightly resembles a class, which will create an instance of something. In this case, the Factory Function will always create a new function.

You can achieve several things with this kind of construction, like creating some kind of counter that maintains an internal and private state:

function createCounter() {
  let current = 0;
  
  function getCurrent() {
    return current;
  }
  
  function increment(step = 1) {
    current += step;
  }
  
  return {
    getCurrent,
    increment
  };
}

const counter1 = createCounter();
counter1.increment(5);
counter1.increment(3);

const counter2 = createCounter();
counter2.increment(4);

console.log('Valor do contador 1:', counter1.getCurrent()); // 8
console.log('Valor do contador 2:', counter2.getCurrent()); // 4

Note that in the example above we no longer return a function, but rather an object with several functions. Note also that each counter has a different state, which is due to the Javascript closujes system. Each function has its own closure, which allows this type of state storage.

This can also be used as a way to achieve dependency injection into functions, so you use the higher function to pass the dependencies and the(s) function(s) returned(s) no longer need to receive this type of value in their arguments. See the difference:

// A nossa "dependência":
const consoleLogSender = {
  send: (message) => console.log(message)
};

function sum(sender, a, b) {
  const result = a + b;
  sender.send(a + b);
}

// Para usar:
sum(consoleLogSender, 2, 2); // 4
sum(consoleLogSender, 3, 5); // 8

Now, with this pattern of Factory Function:

// A nossa "dependência":
const consoleLogSender = {
  send: (message) => console.log(message)
};

function createSum(sender) {
  return function sum(a, b) {
    const result = a + b;
    sender.send(a + b);
  }
}

const consoleLogSum = createSum(consoleLogSender);

consoleLogSum(2, 2); // 4
consoleLogSum(3, 5); // 8

Note that the result is the same, but some people prefer this second way, mainly seeking a decoupled architecture, something in parts achievable by dependency injection.

Now, turning the Arrow functions, the above code can be written as:

// A nossa "dependência":
const consoleLogSender = {
  send: (message) => console.log(message)
};

const createSum = (sender) => (a, b) =>
  sender.send(a + b);

const consoleLogSum = createSum(consoleLogSender);

consoleLogSum(2, 2); // 4
consoleLogSum(3, 5); // 8

However, readability is compromised. I personally will always choose to use function statements in cases like this. In addition, Arrow functions do not have that goal. Sometimes people use something unnecessarily something just for finding "beautiful", which is the case there.

4

Now I understand... I saw this in a course, this resource is called curry or curryng.

Basically it’s used when a Function receives more than one parameter and instead of passing all parameters together into the Function, we pass each separate parameter and return one Function after each parameter.

In your example it did not make much sense because the second parameter was omitted, being only (), but if there was a parameter it would be easier to understand.

To make it easier, let’s have a Function for curry to see the difference:

var soma = (a, b) => { return a + b; }

var somaCurried = (a) => (b) => { return a + b; }

alert(soma(2,3));

alert (somaCurried(2)(3));

See that the result is the same, but in practice, the second Function returns a Function after receiving the first value, and then passes the result to the second.

When I saw this, I explained some applications that I sincerely did not precebi well where to use, but one called my attention: inject a value in one of the functions chain without altering the Function main. Maybe that’s the purpose of this example.

I tried to show an example by taking part of your code and showing how to apply:

var CelularFunction = function(carregador, aparelho) {
  return "Voltagem: " + carregador + ", aparelho:" + aparelho;
};


var CelularCurry = (carregador) => (aparelho) => {
    return "Voltagem: " + carregador + ", aparelho:" + aparelho;
}

// criei uma nova func "injetando" o primeiro valor:
var CelularInject = CelularCurry("500V");

alert(CelularFunction("110v", "Samsung"));
alert(CelularCurry("220v")("Nokia"));

// faço call da function só com o segundo parâmetro, que na prática vai ser passado para a segunda function
alert(CelularInject("Motorola"));

See that in this example, the Function CelularInject, "injects" a value for the first parameter of the string, which goes to the first Function, and then calls the second. The result can be seen when executing.

I hope you can understand the idea. each ()=> with or without parameter generates a Function in the string of curry, that will return a value, and as we have seen, can be manipulated separately, which would take work to do in a Function common.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.