Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

String methods with higher-order functions

Tags:

javascript

I ran into a weird thing while trying to use String methods with higher-order functions. This will throw an error:

['a', 'b'].some('boo'.includes)

I have to wrap the predicate in another function to make it work. But isn't 'boo'.includes already a function?

This works with plain functions:

const boo = {
    includes: () => true
};

['a', 'b'].some(boo.includes)

Is there some special property of String methods that prevents them from being composed like this?

like image 876
sliptype Avatar asked Aug 08 '18 01:08

sliptype


1 Answers

"boo".includes is nothing else than String.prototype.includes. Calling it on the string "boo" however sets this to "boo", which gives the proper context to the function. E.g. "boo".includes("b") is the same as String.prototype.includes.call("boo", "b").

Passing it as an argument, e.g. ['a', 'b'].some('boo'.includes), is the same as ['a', 'b'].some(String.prototype.includes), which then lacks the proper this as context.

You can of course use e.g. bind: ['a', 'b'].some(String.prototype.includes.bind("boo")), or use the optional second parameter thisArg for some: ['a', 'b'].some(String.prototype.includes, "boo"). This will get rid of the error. However, you will then notice, that some passes not only the element, but the index as second parameter, and the array itself as third. This is a problem, as includes also takes an optional second parameter for the start position. This causes likely unwanted behavior, as e.g. the array element "b" is at index 1, and "boo".includes("b", 1) === false.

All in all, you need a function which is so different to String.prototype.includes, that it's just easier to wrap it in a new function that actually does what you want: ['a', 'b'].some(e => "boo".includes(e)), as you already noticed.

like image 149
ASDFGerte Avatar answered Oct 31 '22 15:10

ASDFGerte