Arrow function as a parameter to a function in JavaScript

215 views Asked by At

I'm a beginner/intermediate JavaScript programmer and recently got a couple of exercises handed out on job interviews.

I have to write a function in JavaScript called find that takes two parameters, one of which is an arrow function, containing one parameter. The function should find the appropriate object in an array and return it. I have trouble understanding what the arrow function ((toy) => (toy.type === 'car')) does, how it evaluates, how I can use it. toy is not defined, as can be seen in the example, it is just used as a parameter, which I find extremely confusing and puzzling.

Exercise given:

const toys = [{type: "car", color: "red"}, {type: "ball", color: "blue"}, {type: "teddy-bear", color: "brown"}]

const carToy = find(toys, (toy) => (toy.type === 'car'));

console.log(carToy); // expected output: {type: "car", color: "red"}

What I wrote:

function find(array, toy) {
    console.log(toy); // [Function (anonymous)]
    toy(); // TypeError: Cannot read properties of undefined (reading 'type')
    console.log(toy()); // TypeError: Cannot read properties of undefined (reading 'type')
} 

At first I thought that toy would evaluate to the string "car", but it doesn't. console.log() inside a find function returns either undefined or [Function (anonymous)].

If I got a string I could easily solve the problem, but the arrow function has had me stuck for over an hour. I have tried to find a solution online, but nothing helped me understand this.

Would love to get some pointers on how to solve this and any in depth resources that would teach me more about arrow functions.

3

There are 3 answers

1
Armand On

Looks like you need to implement the find method.

What is happening is that the function is passed as a parameter, so to be able to call that function you need to pass it a object of type toy.

Something like this, didn't test it so might require a tweak or two

function find(array, toy) {
    for(var i in array) {
        if(toy(array[i])
             return array[i];
    }
    return null;
} 

You can read this Article for a tutorial about this subject

0
The Man Who Sold The World On

The name of the "arrow" function is actually a form of creating an anonymous function, so that is why that is returned.

An anonymous function is a function without a name. You invoke it by its variable, but not by its function name (the name followed by the 2 brackets: "()")

1
Mulan On

JavaScript has many ways to do the same things. As a beginner, it's easy to become confused and understand some of the differences.

I have to write a function in JavaScript called find that takes two parameters, one of which is an arrow function, containing one parameter

The first thing to note is that arrow functions differ from ordinary functions only in syntax and context. Every arrow function can be expressed as a non-arrow function. For a few notes on the subtle differences, you can read the arrow function docs -

  1. inherit this from the parent scope
  2. do not have arguments or super
  3. cannot be used as constructor function
  4. cannot be used as generator function

I have trouble understanding what the arrow function ((toy) => (toy.type === 'car')) does

Intuitively it is a function that says, Give me a toy, I will tell you if it is a car.

Here it is as a function expression -

(function(toy) {
  return toy.type === "car"
})

Maybe it helps to see it as a named function -

function isCar(toy) {
  return toy.type === "car"
}

At first I thought that toy would evaluate to the string "car", but it doesn't

The === operator returns a boolean, not a string. The function will return true only if toy.type is equal to the string literal "car".


In your program -

function find(array, toy) {
    console.log(toy); // [Function (anonymous)]
    toy(); // TypeError: Cannot read properties of undefined (reading 'type')
    console.log(toy()); // TypeError: Cannot read properties of undefined (reading 'type')
} 

It's a little confusing to talk about because -

  1. in the exercise the arrow function has a parameter named toy
  2. in your attempt, the name of the arrow function is also toy

Let's write ours as fn and make some comments about what we now understand -

function find(array, fn) {
  // given fn is a function that takes a item and returns a boolean
  // given array is an array of items
  // find the item where fn(item) is true

  // look in the items
  for (const item of array) {
    // complete the program ...
  }
}

Something worth mentioning is that you should strive to write all functions with -

  1. well-defined inputs
  2. well-defined output
  3. no side effects (like console.log, throw, etc)

Writing some basic docs for the function is helpful. A common format is jsDoc -

/**
 * Searches for the first element in an array that satisfies the provided testing function.
 * @param {Array} items - The array to search through.
 * @param {function} fn - The testing function, which should return `true` for the desired element.
 * @returns {any|null} Returns the first element that satisfies the provided testing function, or `null` if no such element is found.
 */
function find(items, fn) {
  // ...
}

I find it a lot easier to think when all of those items are laid out plainly. Other tools take this further and implement a complete type system to ensure the correctness of your implementation. Such an example in TypeScript would look like this

function find<T>(items: Array<T>, fn: (item: T) => boolean): null | T {
  for (const item of items) {
    // ...
  }
  return null
}

Even if you choose neither approach for your code, you should still be thinking about these principles in practice. Functions are essential for building good abstractions, so it's critical we learn good patterns and how to identify bad ones.