Can someone explain this regular array filtering

I am filtering an array and found a regex here. I am trying to figure this out:

filterArray.filter(/./.test.bind(new RegExp(key, 'g'))) 

But I don’t understand how an array checks its value for a regular expression or why you should start with /./ and not just write a regular expression. And how to tie the work in this case?

EDIT: The key is just the string I want to match, “hello” or “dog” or “anything really”.

+8
javascript regex
source share
2 answers

The .bind() method returns a function with what you passed as the first argument, bound as the value of this .

Since you call .bind() from .test() , you get the .test() method with this binding on new RegExp(key, 'g') .

/./ doesn't matter here. This is just a shortcut to the RegExp.prototype.test method.

As a result, you will really do:

 var regexp = new RegExp(key, 'g'); filterArray.filter(function(val) { return regexp.test(val); }); 

You should notice that this is a little dangerous, because the regex object with modifier g has state. This means that it always starts a new search where the previous one stopped.

Given this filtering scenario, g doesn't seem to be necessary at all and can really cause problems.

Here is an example of the dangers of using g here:

 var re = /./.test.bind(new RegExp("foo", 'g')); var str = "foobar"; console.log(re(str)); // true console.log(re(str)); // false 

Therefore, calling the same regular expression on the same line leads to two different results. If we call it again, it will be true again.


Therefore, given the use of .filter() as a callback, let's say key is "foo" , then let's say that one val is "foobar" . This is allowed through the filter.

But let's say that the next val is "foobaz" . The search will resume on the fourth character instead of starting with the first, so "foo" will not be found.


Here is a concrete example that shows the problem in action:

DEMO: http://jsfiddle.net/s9PzL/

 var filterArray = [ "foobar", "foobaz", "foobuz", "foobix" ]; var result = filterArray.filter(/./.test.bind(new RegExp("foo", 'g'))); 

All lines have "foo" , so they must all go through. But the result shows that this is not happening.

 document.body.textContent = result.join(", "); // foobar, foobuz 
+14
source share

I think the reason is that this is done so because you want to execute a testing method for each element of the array. Just passing the testing method to filter (presumably) will ruin the method binding.

This is why in your example:

 /./ 

Creates an empty regex

 /./.test 

is a test method for this regex

 /./.test.bind(new Regex(..)) 

binds this method to the requested method and returns a new method that executes test , where this is the key based regular expression you provided.

It seems that this could be written much more clearly:

 RegExp.prototype.test.bind(new RegExp(key, 'g')) 
+6
source share

All Articles