1

Bare with my newbness if you can, I am just trying to understand exactly what is going on in this function so I can better tailor it to my use case, and write cleaner/shorter code when needed. The function works of course and I can use it, but it bugs me when I don't fully understand the code I am using. I think I understand for the most part but I am having a hard time putting all of the pieces together. If this is a duplicate then all apologies and please mark it as such but I could not find an exact answer to what I am trying to understand. From other answered questions and outside articles I have been able to understand most of what is going on, but I am still getting stuck on a couple of points.

The exact code is:

const userBy = id => u => u.id == id; 
const users = [{ id: 1, name: "Kaio" }, { id: 2, name: "Gabriella" }, { id: 3, name: "Enzo" }];
const id = 2;
const user = users.find(userBy(id));

With my main question centering around:

const userBy = id => u => u.id == id;

I got the code from this article just in case more context is needed, though the aforementioned code should be enough - https://medium.com/@kaiosilveira/mastering-javascript-arrays-beyond-for-and-foreach-loops-e2ecf9dfe3e

I understand that in the 'userBy' function that 'id' is being passed in as the parameter. I also understand that in the shorthand syntax the return statement is implied, and that the find() method has three parameters of it's own (element, index, array), much like a forEach() function which I understand and use often.

To put it all together - I understand that 'id' is being passed in as a parameter, but then if I understand it correctly 'u' is being returned and/or passed in as a parameter of the final function where the specified property 'id' of 'u' is equal to the parameter 'id' that was passed into the original function. And since I know that the find() method is iterating over an array, I can reasonably deduce that 'u' is the current element/index of that array.

The specific part that I am having a hard time understanding is how 'u' is capturing the element/index as it's value. Also why 'u' needs to be in it's own function instead of as another parameter alongside the 'id' parameter of the initiating function.

Like I said, the function works and all is well regardless if I understand it. But I would greatly appreciate anyone who could take the time to explain it to me exactly what is happening. I've researched and understood all that I can on my own, just need a little hand holding on those last few points that I mentioned.

[Post Answered Edit] It was asking me to explain why this question was different from What do multiple arrow functions mean in javascript? . They are very similar, but I think with my specific situation with the added Array.prototype.find method differentiates it enough to warrant it's own explanation. At it's core though I can see how some might label it as the same, so if others feel that way then by all means mark it as a duplicate. Whatever is best for the community is fine by me, I am just grateful that the community took the time to help me understand my question.

zentao
  • 15
  • 1
  • 5
  • I can't provide an answer for you but check out this idea from functional programming: https://stackoverflow.com/questions/36314/what-is-currying – Matt Pengelly Mar 15 '19 at 19:43
  • It's a curried function. `userBy(id)` returns a function which is used as callback to `find`: [What do multiple arrow functions mean in javascript?](https://stackoverflow.com/questions/32782922) – adiga Mar 15 '19 at 19:44
  • So rewritten without fat arrow: `const userBy = function(id) { return function (u) { return u.id == id } }` So first call is setting the id and returns the function. So then when find executes, it passes `u` to the function. – epascarello Mar 15 '19 at 19:48
  • `u` is passed to the output function by `[].find()` `id` is memorized via closure to be whatever you set it to when you call the wrapper. – dandavis Mar 15 '19 at 19:48
  • Thanks Matt and adiga for pointing out currying, appreciate the info. Also thanks everyone else, as with the other answers you helped me realize the point I missing. Much appreciated all. – zentao Mar 15 '19 at 20:08

2 Answers2

0

First, let's look at what .find is doing. The implementation of .find looks something like this:

Array.prototype.find = function (callback) {
  for (let i = 0; i < this.length; i++) {
    const match = callback(this[i], i, this);
    if (match) {
      return this[i];
    }
  }
}

Find expects you to pass it a function, and that function will be called repeatedly, passing in each element of the array one at a time (plus the index and the array), until one of them passes the test. So a normal use of this would be something like this, to find the user who's id is 2:

users.find((user) => {
  if (user.id === 2) {
    return true;
  }
  return false;
});

Or shorter:

users.find(user => user.id === 2);

Now the code you've shown goes one step further. It foresees the possibility of wanting to find user.id === 2, but also user.id === 1, and user.id === 18273, etc. So they've created a helper function named userBy, which can produce other functions. In other words, this code:

const userBy = id => u => u.id == id; 

... is a factory for producing functions that look like user => user.id === 2, except it can create functions not just that compare against 2, but whatever id you want.

So with that in hand, a line of code that looks like this:

const user = users.find(userBy(2));

... basically means "create the function user => user.id === 2, and then pass that into users.find"

Nicholas Tower
  • 72,740
  • 7
  • 86
  • 98
  • Even more clarification, greatly appreciated as that was even more precise in it's explanation. As with the other answers, I really appreciate you taking the time to answer. – zentao Mar 15 '19 at 20:03
0

It's because the userBy function doesn't actually iterate over the array - Array.find takes a function with a Boolean return value, therefore the function doing the actual finding is the anonymous child function u => u.id == id. Here's how it'd look in ES5:

var userBy = function(id) {
    return function(u) {
        u.id == id;
    };
};

Here, the userBy function is returning a callback/testing function, and this is used in Array.find. If you didn't have to pass id as an argument, you could simplify it like so, by only using the inner function:

const userBy = u => u.id == id;
const user = users.find(userBy);
Jack Bashford
  • 43,180
  • 11
  • 50
  • 79
  • Thank you, that cleared it up nicely. I was completely missing the point that 'userBy' was passing a function into the find() method and that that was doing the actual iterating. I appreciate your help in understanding, many thanks. – zentao Mar 15 '19 at 19:58
  • No problem @z4nta0, if my answer solved your problem please mark it as accepted by clicking the grey tick mark to the left of my answer. – Jack Bashford Mar 15 '19 at 20:16
  • I can only choose 1 'accepted' answer and I chose Nicholas' answer simply because it explained it in more detail. I appreciate you taking the time though and your answer did help me understand regardless. – zentao Mar 15 '19 at 20:37