I'm filtering an array, and found a regex on here. I'm trying to understand this:
filterArray.filter(/./.test.bind(new RegExp(key, 'g')))
But I don't understand how the array tests it value against the regex or why you have to start with /./ instead of just writing the regex. And how does bind work in this case?
EDIT: Key is just a string that I want to match, "hi" or "dog" or "anything really".
The .bind()
method will return a function with whatever you passed as the first argument bound as the value of this
.
Since you're calling .bind()
from .test()
, you're getting the .test()
method with the this
bound to new RegExp(key, 'g')
.
The /./
is irrelevant here. It's just short way of getting to the RegExp.prototype.test
method.
The result is that you'll effectively be doing:
var regexp = new RegExp(key, 'g');
filterArray.filter(function(val) {
return regexp.test(val);
});
You should note that this is a little bit dangerous, because a regex object with the g
modifier is stateful. This means it always starts a new search where the previous one left off.
Given this filtering scenario, the g
doesn't seem at all necessary, and could really only cause problems.
Here's an example of the danger of using the g
here:
var re = /./.test.bind(new RegExp("foo", 'g'));
var str = "foobar";
console.log(re(str)); // true
console.log(re(str)); // false
So calling the same regex on the same string produces two different results. If we called it again, it would be true
once again.
So given the use as a .filter()
callback, let's say key
is "foo"
, then lets say one val
is "foobar"
. It will be allowed through the filter.
But let's say the very next val
is "foobaz"
. The search will resume on the fourth character instead of starting from the first, so the "foo"
will not be found.
Here's concrete example that shows the issue in action:
DEMO: http://jsfiddle.net/s9PzL/
var filterArray = [
"foobar",
"foobaz",
"foobuz",
"foobix"
];
var result = filterArray.filter(/./.test.bind(new RegExp("foo", 'g')));
All the strings have "foo"
, so they should all get through. But the result shows that doesn't happen.
document.body.textContent = result.join(", "); // foobar, foobuz
I think the reason this is done this way is because you want to execute the test method on each item in the array. Just passing the test method to filter will (presumably) mess up the binding of the method.
That's why in your example:
/./
Generates an empty regex
/./.test
is the test method on that regex
/./.test.bind(new Regex(..))
binds that method to the requested method, and returns a new method that executes test
where this
is your supplied regex based on key
.
It seems that it could have been written a lot more clear:
RegExp.prototype.test.bind(new RegExp(key, 'g'))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With