简体   繁体   中英

Javascript: point-free style in callback

So I wanted the elements of the array arr1 that also happen to belong to the array arr2 . I figured arr1.filter(arr2.includes) should do the trick, but it gave me an error (see below). Strangely, though, arr1.filter(x => arr2.incudes(x)) worked fine. Even though the functions arr2.includes and x => arr2.includes(x) aren't referentially equal, shouldn't they take the same values on the same inputs? What am I missing, here?

> arr1 = ['a', 'b', 'c']
[ 'a', 'b', 'c' ]
> arr2 = ['a', 'c', 'd']
[ 'a', 'c', 'd' ]
>
> arr1.filter(x => arr2.includes(x))
[ 'a', 'c' ]
> arr1.filter(arr2.includes)
TypeError: Cannot convert undefined or null to object
    at includes (<anonymous>)
    at Array.filter (native)
    at repl:1:6
    ... etc ...

There are two reasons you can't just do arr1.filter(arr2.includes) :

  1. arr2.includes is just a reference to the function, but what you need is both a reference to the function and to the array that you want to use it on ( arr2 ). You could solve that by using Function.prototype.bind , but:

  2. filter passes its callback multiple arguments, not just one: It passes the value, its index, and the original array. includes will try to use the second argument it receives as the index at which to start searching, so when filter passes it the index, it'll use that and skip leading entries.

So the usual solution is to use a wrapper function that knows it needs to use includes on arr2 and knows to only pass it the one argument — which is what you've done with your arrow function.

But see also Michał Perłakowski's answer for an answer from the functional programming perspective using a utility function to create the callback function rather than creating it inline.

Here's how you could implement an includes function that could be used in point-free style:

 const arr1 = ['a', 'b', 'c']; const arr2 = ['a', 'c', 'd']; const includes = arr => x => arr.includes(x); console.log(arr1.filter(includes(arr2))); 

If you're interested in functional programming in JavaScript, you should try the Ramda library. With Ramda your code could look like this:

 const arr1 = ['a', 'b', 'c']; const arr2 = ['a', 'c', 'd']; // First option: R.flip console.log(R.filter(R.flip(R.contains)(arr1), arr2)); // Second option: R.__ (placeholder argument) console.log(R.filter(R.contains(R.__, arr1), arr2)); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.24.1/ramda.min.js"></script> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM