1

I have a file with the following code:

const logger = (options) => (req, res, next) => {
  if (typeof options === 'object'
      && options !== null
      && options.enable) {
        console.log(
          'Status Code:', res.statusCode,
          'URL:', req.originalUrl,
        )
  }
  next()
}

module.exports = logger

It is used as such in a different .js file:

const express = require('express')
const loggerMiddleware = require('./middleware-logger')
const app = express()

app.use(loggerMiddleware({
        enable: true,
}))

app.listen(
    1337,
    () => console.log('Web Server listening on 1337'),
)

Can anyone explain what is happening with the series of => in the first line? I understand a normal (req,res,next) => {} to mean something like:

"There is an unnamed function with 3 arguments defined by what is in the curly braces.

In this case with the series of arrow operators, what I do not "get" is how the function def can see all the arguments in both (options) and (req,res,next) at the same time.

What is really going on here under the hood? Does this have something to do with promises? And again, how can the one method def see all the arguments at the same time?

4
  • Simple answer is it is a function that returns another function Commented Sep 11, 2018 at 17:10
  • There are two functions. The first one, which will be the value of logger, takes one argument: the options. The other function is returned whenever logger is called. Commented Sep 11, 2018 at 17:10
  • It is called currying. which as @charlietfl and the others in comment all mentioned the functionality. Here is a blog someone wrote on it currying in ES6 in particular. blog.benestudio.co/currying-in-javascript-es6-540d2ad09400 Commented Sep 11, 2018 at 17:16
  • @Jacob it is really similar to currying. But if you talk currying you normally mean to fix one or more arguments of a function that expects mulpible arguments. Commented Sep 11, 2018 at 17:28

1 Answer 1

5

The code you have shown is a shorthand for:

const logger = function(options) {
  return function(req, res, next) {
    if (typeof options === 'object' &&
      options !== null &&
      options.enable) {
      console.log(
        'Status Code:', res.statusCode,
        'URL:', req.originalUrl,
      )
    }
    next()
  }
}

If you call loggerMiddleware({enable: true,}) it will return a new function function(req, res, next) { ... } that creates a closure over the options parameter.

This allows this returned function (in this case a middleware) have access to the passed option object on each request without the need of polluting the global scope.

And as of that also allows to create two middlewares with differnt options:

app.get('/with-logging', loggerMiddleware({
  enable: true,
}), function(res, res) {})


app.get('/without-logging', loggerMiddleware({
  enable: false,
}), function(res, res) {})

Personally I think those (options) => (req, res, next) => { constructs are not really readable and remindes me of those fancy nested ternary conditional operator (?:) cobinations.

Sign up to request clarification or add additional context in comments.

3 Comments

Well, nested ternaries get pretty wacky after anything past two expression conditions. I use ternaries a lot and only recently the other day used currying for a handleClick() in my React component., was the only way I could think of to initialize the property.
@Jacob closures and currying is great. What I wanted to say is that function(option) { return (req, res, next) => { } } or function(option) { return function(req, res, next) { } } is most of the time easier to read then (options) => (req, res, next) => {. Arrow functions are often overused, just because they are fancy and the code is shorter.
I cant argue with people getting too caught up in the newest hotness. How it goes too is always make it work first!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.