Steve Bennett
Steve Bennett

Reputation: 126125

Can't use String.prototype.match as function for Array.some?

This doesn't work:

var s = '^foo';
console.log(['boot', 'foot'].some(s.match));

Uncaught TypeError: String.prototype.match called on null or undefined

But this does:

var s = '^foo';
console.log(['boot', 'foot'].some(function(i) { return i.match(s) }));

Why is this? I imagine somehow the String.prototype.match function is too "primitive" or something, but why exactly? Since I'm not using ES2015, the second version seems quite verbose. Is there an alternative?

EDIT

When I wrote the above, I actually got it backwards compared to my actual need, which was matching one string against a number of regexes. But thanks to the great answers and comments below, I get it: [/^foo/, /^boo/].some(''.match, 'boot').

Upvotes: 7

Views: 1512

Answers (2)

Mark Reed
Mark Reed

Reputation: 95242

A function value in Javascript does not bring its object along with it. The value of s.match is a plain function value, with no knowledge that you happened to find it attached to s. In fact, no matter what String you access it through, it's always the same function value:

"foo".match === "bar".match 
//= true

When you call a function through an object, Javascript sets this to that object for the duration of the function call. But as soon as anything comes between retrieving the function value and calling it, any object association is lost.

You can create a function that does remember a specific this value using bind, as in @Felix King's answer. someFunction.bind(someObject) has approximately the same meaning as function(arg1, arg2,...) { return someObject.someFunction(arg1, arg2,...); }, but it automatically handles the number of parameters properly.

Upvotes: 4

Felix Kling
Felix Kling

Reputation: 816364

Note: The value of this is determined by how the function is called! (exception: bound and arrow functions)

If you pass s.match to .some, then the function will be called with this set to the global object (e.g. window) not the string it "belongs" to.

I.e. it would be equivalent to this:

String.prototype.match.call(window, 'foo')

This cannot work because this has to refer to a string object.

You could solve this by binding the function to a specific this value:

['boot', 'foot'].some(s.match.bind(s));

Learn more about this:

Upvotes: 8

Related Questions