Difference between RegExp constructor and Regex literal test function? [duplicate] - javascript

This question already has answers here:
Why does a RegExp with global flag give wrong results?
(7 answers)
Closed 6 years ago.
I'm confused on how this is possible...
var matcher = new RegExp("d", "gi");
matcher.test(item)
The code above contains the following values
item = "Douglas Enas"
matcher = /d/gi
Yet when I run the matcher.test function back to back I get true for the first run and false for the second run.
matcher.test(item) // true
matcher.test(item) // false
If I use a regexp literal such as
/d/gi.test("Douglas Enas")
and run it back to back in chrome I get true both times. Is there an explanation for this?
Sample of a back to back run in chrome console creating a regexp object using constructor
matcher = new RegExp("d","gi")
/d/gi
matcher.test("Douglas Enas")
true
matcher.test("Douglas Enas")
false
matcher
/d/gi
Sample using back to back calls on literal
/d/gi.test("Douglas Enas")
true
/d/gi.test("Douglas Enas")
true
The reason for this question if because using the RegExp constructor and the test function against a list of values I'm losing matches... However using the literal I'm getting back all the values I expect
UPDATE
var suggestions = [];
////process response
$.each(responseData, function (i, val)
{
suggestions.push(val.desc);
});
var arr = $.grep(suggestions, function(item) {
var matcher = new RegExp("d", "gi");
return matcher.test(item);
});
Moving the creation of the matcher inside the closure included the missing results. the "d" is actually a dynamically created string but I used "d" for simplicity sake. I'm still not sure now creating a new expression every time I do the test when I am iterating over the suggestions array would inadvertently exclude results is a little confusing still, and probably has something to do with the advancement of the match test

From RegExp.test():
test called multiple times on the same global regular expression instance will advance past the previous match.
So basically when you have an instance of RegExp, each call to test advances the matcher. Once you've found the first d, it will look beyond that and try to find another d. Well, there are none anymore, so it returns false.
On the other hand, when you do:
/d/gi.test("Douglas Enas")
You create a new RegExp instance every time on the spot, so it will always find that first d (and thus return true).

According to Mozilla Developer Network,
As with exec (or in combination with it), test called multiple times
on the same global regular expression instance will advance past the
previous match.
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/test

I can't find the link ATM, but as I recall, this is a known issue with the test method in combination with a g pattern: the match position isn't "forgotten" somehow. Either drop the global flag and/or use the .match method, and it'll work just fine.

Related

What does this javascript function do?

var n = {
Android: /Android/i.test(navigator.userAgent),
Safari: /iPhone|iPad|iPod/i.test(navigator.userAgent) && !/CriOS|Chrome|Mercury/.test(navigator.userAgent)
};
I am curious about the /Android/i.test() function. If this a function in another file? I'm guessing it is not since the next function /iPhone|iPad|iPod/i.test() is even more curious. Is it a string compare on the 'Android' string? Could anyone provide me with some documentation?
It's a method call on the regular expression /Android/i.
The /Android/i part represents a regular expression or "regex", which is used to do pattern-matching on strings.
A regular expression has a method called test, and returns true if it matches. You could rewrite that hunk above as:
androidRegex = /Android/i;
safariRegex = /iPhone|iPad|iPod/i;
criOsregex = /CriOS|Chrome|Mercury/;
var n = {
Android: androidRegex.test(navigator.userAgent),
Safari: safariRegex.test(navigator.userAgent) && !criOsregex.test(navigator.userAgent)
};
The syntax for declaring a regular expression in Javascript is /pattern/flags, where pattern is the pattern to compare against, and flags are additional options.
The Android one is very simple: it just compares against the string Android, with the flag i to make it case-insensitive.
The Safari one is slightly more complex, because it uses "alternation" to match iPhone, iPad, or iPod. The | character delimits alternates in a regex.
The CriOS regex, notably, leaves off the i flag because the author wants it to be case-sensitive (the default).
The var n is declared as an object with two properties which are called Android and Safari.
When the object is initialized, both properties are executed returning a boolean result either the User Agent of the Navigator is Android for the first one, or iPhone, iPad or iPod for the second one.
Therefore, you can expect both properties to be either true or false.
EDIT: As #N3dst4 stated, this is called regular expression. See his reply for more info about it.

Node.js global variables and functions with square brackets - why does this work?

I have module that returns an object to a callback with the structure of the following pseudocode:
module.exports=function(){
global.foo=function(){
var callbacks=Array.prototype.slice.call(arguments,1);
var conf=arguments[0];
return global[callbacks.shift()].apply(null,[conf,callbacks]);
}
global.bar=function(){
var callbacks=Array.prototype.slice.call(arguments,1);
var conf=arguments[0];
return global[callbacks.shift()].apply(null,[conf,callbacks]);
}
// This one is where i ran into trouble
global.foobar=function(){
var callbacks=Array.prototype.slice.call(arguments,1);
var conf=arguments[0];
// right here
if(callbacks.length===[].length){
return global[callbacks.shift()].apply(null,[conf,callbacks]);
}
}
var conf={'pseudo':'object'};
return global['foo'](conf,'foo','bar','foobar');
}
Everything works fine until foobar, and what happens is that when I get down to checking if there are anymore callbacks - because if their are, I want to call them - callbacks.length is 1 at this point. This didn't make sense to me, and I discovered that at that point callbacks actually equaled [[]]. I don't know why this is getting returned, so I guess I have two questions. Can anyone see why callbacks is equal to [[]]?
What I discovered along the way is that when using Strings called as functions in the global namespace - as in var bar='foo'; global[bar]() calls global.foo() - multiple brackets are ignored. So for example, global[[[[[[['foo']]]]]]] === global['foo']. Also weirdly enough (at least to me), the following:
// With
global.bar='foo';
global.foo=function(){return true;}
//the following
global[global[bar]]()
// throws a TypeError: undefined is not a function
None of that makes sense to me.
I recognize that this question ends up asking three questions, and is a bit disorganized, but frankly I'm a bit confused, and I'm not really sure how I want to ask what I want to know, so I just said everything.
My main questions is regarding the multiple brackets, and why that works.
Thanks
My main questions is regarding the multiple brackets, and why that
works.
The multiple brackets works only because it's trying to do a string conversion to get a property name. So, no matter how many nested arrays you have, it ends up calling .toString() on each array and since the inner array only has a single item that has a string in it, multiple .toString() calls just end up resolving to the inner string.
Here's a demo of the same concept in a browser:
window.foo = "hi"
document.write(window[[[[["foo"]]]]]);
For some further explanation:
["foo"].toString() === "foo";
So, then:
[["foo"].toString()].toString() === "foo"
But, if the outer .toString() is there, it is already driving things to a string so you can remove the inner .toString() and thus you get:
[["foo"]].toString() === "foo"
And, you can then nest it as many levels as you want as long as something on the outer level is driving it to a string.
And, since property names are always strings, when you do:
global[[[[[[['foo']]]]]]]
You're ultimately asking for a property name that can be looked up on the global object and since the property name is a string, that calls .toString() on the outer array. When the outer array goes to convert it's only item to a string, it asks that one item to convert itself to a string so this:
global[[[[[[['foo']]]]]]]
turns into this:
global[[[[[[['foo'].toString()].toString()].toString()].toString()].toString()].toString()]
Which hopefully explains why you end up with nothing more than this in the end:
global["foo"]
FYI, if you look at the ES5/ES6 spec for Array.prototype.toString(), it ends up calling array.join() which for a single element array just ends up doing a .toString() on that single element which is how it causes all the nested arrays to just call .toString() on themselves. The outer array calls .toString() on the first nested array which called .toString() on it's single item which is the next nested array and so on until it finally gets to the inner string which is returned back from all the .toString() calls. And, it matters not how many arrays deep it is nested.
Spec reference for Array.prototype.toString(): http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.tostring
Spec reference for Array.prototype.join() which is called by Array.prototype.toString(): http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.join
In your other scenario here:
// With
global.bar='foo';
global.foo=function(){return true;}
//the following
global[global[bar]]()
// throws a TypeError: undefined is not a function
None of that makes sense to me.
Here's what is going on in global[global[bar]]() one piece at a time:
bar resolves to the string 'foo'.
So, global[bar] resolves to global['foo'] which is your function.
But, then you try to do another global reference on it like this global[global[bar]], then you are essentially trying to do:
global[yourfunction]
or
global[global.foo]
That will try to convert yourfunction to a string and look up that property on the global object. That will be undefined. So, you will then try to do undefined() which is a TypeError because undefined is not a function.
What will work in this case is just:
global[bar]()

Javascript literal regexp vs RegExp object, instances inside loops

I have the following two js example codes, one using literal regexp and the other one using RegExp object:
"use strict";
var re;
// literal regexp
for(var i = 0; i<10; i++)
{
re = /cat/g;
console.log(re.test("catastrophe"));
}
// RegExp constructor
for(var i = 0; i<10;i++)
{
re = new RegExp("cat", "g");
console.log(re.test("catastrophe"));
}
Some books say that using the first example "true" should be printed on each second iteration given the fact that the using the literal expression there will be created only one instance of RegExp. So the loop finds on the first run the substring "cat", than on the second run continues from where is left and finds nothing. On the third run it starts from the beginning and so on. I've tested this but it seems that in both examples i get the count of 10.
Can you explain why this is happening?
The 3rd Edition ECMAScript (JavaScript) specification allowed caching and reusing regular expression literals, including their state, leading to the "surprising" behavior you mention in relation to your first code example, which certainly looks like it should create a new regular expression object on every loop. That caching of literals was not implemented by most engines and was a phenomenally bad idea, and the 5th Edition specification fixes it.
I believe all modern engines that used to do caching (primarily SpiderMonkey, Firefox's engine) were updated accordingly. A new regex is created for every iteration in both of your examples.
More in this blog post (right at the end) by Steven Levithan, and in the fourth paragraph of Annex E in the specification:
7.8.5: Regular expression literals now return a unique object each time the literal is evaluated. This change is detectable by any programs that test the object identity of such literal values or that are sensitive to the shared side effects.
In both cases, you are creating a new RegExp each time through the for loop. It doesn't matter which way you declare the RegExp - it's still creating a new one each time the loop iterates. Thus, you get the same behavior.
Now, if you initialized the re variable before the for loop, you would get a different behavior because of the persistence of the same RegExp object and how it uses the g flag.

Dynamic vs Inline RegExp performance in JavaScript

I stumbled upon that performance test, saying that RegExps in JavaScript are not necessarily slow: http://jsperf.com/regexp-indexof-perf
There's one thing i didn't get though: two cases involve something that i believed to be exactly the same:
RegExp('(?:^| )foo(?: |$)').test(node.className);
And
/(?:^| )foo(?: |$)/.test(node.className);
In my mind, those two lines were exactly the same, the second one being some kind of shorthand to create a RegExp object. Still, it's twice faster than the first.
Those cases are called "dynamic regexp" and "inline regexp".
Could someone help me understand the difference (and the performance gap) between these two?
Nowadays, answers given here are not entirely complete/correct.
Starting from ES5, the literal syntax behavior is the same as RegExp() syntax regarding object creation: both of them creates a new RegExp object every time code path hits an expression in which they are taking part.
Therefore, the only difference between them now is how often that regexp is compiled:
With literal syntax - one time during initial code parsing and
compiling
With RegExp() syntax - every time new object gets created
See, for instance, Stoyan Stefanov's JavaScript Patterns book:
Another distinction between the regular expression literal and the
constructor is that the literal creates an object only once during
parse time. If you create the same regular expression in a loop, the
previously created object will be returned with all its properties
(such as lastIndex) already set from the first time. Consider the
following example as an illustration of how the same object is
returned twice.
function getRE() {
var re = /[a-z]/;
re.foo = "bar";
return re;
}
var reg = getRE(),
re2 = getRE();
console.log(reg === re2); // true
reg.foo = "baz";
console.log(re2.foo); // "baz"
This behavior has changed in ES5 and the literal also creates new objects. The behavior has also been corrected in many browser
environments, so it’s not to be relied on.
If you run this sample in all modern browsers or NodeJS, you get the following instead:
false
bar
Meaning that every time you're calling the getRE() function, a new RegExp object is created even with literal syntax approach.
The above not only explains why you shouldn't use the RegExp() for immutable regexps (it's very well known performance issue today), but also explains:
(I am more surprised that inlineRegExp and storedRegExp have different
results.)
The storedRegExp is about 5 - 20% percent faster across browsers than inlineRegExp because there is no overhead of creating (and garbage collecting) a new RegExp object every time.
Conclusion:
Always create your immutable regexps with literal syntax and cache it if it's to be re-used. In other words, don't rely on that difference in behavior in envs below ES5, and continue caching appropriately in envs above.
Why literal syntax? It has some advantages comparing to constructor syntax:
It is shorter and doesn’t force you to think in terms of class-like
constructors.
When using the RegExp() constructor, you also need to escape quotes and double-escape backslashes. It makes regular expressions
that are hard to read and understand by their nature even more harder.
(Free citation from the same Stoyan Stefanov's JavaScript Patterns book).
Hence, it's always a good idea to stick with the literal syntax, unless your regexp isn't known at the compile time.
The difference in performance is not related to the syntax that is used is partly related to the syntax that is used: in /pattern/ and RegExp(/pattern/) (where you did not test the latter) the regular expression is only compiled once, but for RegExp('pattern') the expression is compiled on each usage. See Alexander's answer, which should be the accepted answer today.
Apart from the above, in your tests for inlineRegExp and storedRegExp you're looking at code that is initialized once when the source code text is parsed, while for dynamicRegExp the regular expression is created for each invocation of the method. Note that the actual tests run things like r = dynamicRegExp(element) many times, while the preparation code is only run once.
The following gives you about the same results, according to another jsPerf:
var reContains = /(?:^| )foo(?: |$)/;
...and
var reContains = RegExp('(?:^| )foo(?: |$)');
...when both are used with
function storedRegExp(node) {
return reContains.test(node.className);
}
Sure, the source code of RegExp('(?:^| )foo(?: |$)') might first be parsed into a String, and then into a RegExp, but I doubt that by itself will be twice as slow. However, the following will create a new RegExp(..) again and again for each method call:
function dynamicRegExp(node) {
return RegExp('(?:^| )foo(?: |$)').test(node.className);
}
If in the original test you'd only call each method once, then the inline version would not be a whopping 2 times faster.
(I am more surprised that inlineRegExp and storedRegExp have different results. This is explained in Alexander's answer too.)
in the second case, the regular expression object is created during the parsing of the language, and in the first case, the RegExp class constructor has to parse an arbitrary string.

How often does JavaScript recompile regex literals in functions?

Given this function:
function doThing(values,things){
var thatRegex = /^http:\/\//i; // is this created once or on every execution?
if (values.match(thatRegex)) return values;
return things;
}
How often does the JavaScript engine have to create the regex? Once per execution or once per page load/script parse?
To prevent needless answers or comments, I personally favor putting the regex outside the function, not inside. The question is about the behavior of the language, because I'm not sure where to look this up, or if this is an engine issue.
EDIT:
I was reminded I didn't mention that this was going to be used in a loop. My apologies:
var newList = [];
foreach(item1 in ListOfItems1){
foreach(item2 in ListOfItems2){
newList.push(doThing(item1, item2));
}
}
So given that it's going to be used many times in a loop, it makes sense to define the regex outside the function, but so that's the idea.
also note the script is rather genericized for the purpose of examining only the behavior and cost of the regex creation
From Mozilla's JavaScript Guide on regular expressions:
Regular expression literals provide compilation of the regular expression when the script is evaluated. When the regular expression will remain constant, use this for better performance.
And from the ECMA-262 spec, §7.8.5 Regular Expression Literals:
A regular expression literal is an input element that is converted to a RegExp object (see 15.10) each time the literal is evaluated.
In other words, it's compiled once when it's evaluated as a script is first parsed.
It's worth noting also, from the ES5 spec, that two literals will compile to two distinct instances of RegExp, even if the literals themselves are the same. Thus if a given literal appears twice within your script, it will be compiled twice, to two distinct instances:
Two regular expression literals in a program evaluate to regular expression objects that never compare as === to each other even if the two literals' contents are identical.
...
... each time the literal is evaluated, a new object is created as if by the expression new RegExp(Pattern, Flags) where RegExp is the standard built-in constructor with that name.
The provided answers don't clearly distinguish between two different processes behind the scene: regexp compilation and regexp object creation when hitting regexp object creation expression.
Yes, using regexp literal syntax, you're gaining the performance benefit of one time regexp compilation.
But if your code executes in ES5+ environment, every time the code path enters the doThing() function in your example, it actually creates a new RegExp object, though, without need to compile the regexp again and again.
In ES5, literal syntax produces a new RegExp object every time code path hits expression that creates a regexp via literal:
function getRE() {
var re = /[a-z]/;
re.foo = "bar";
return re;
}
var reg = getRE(),
re2 = getRE();
console.log(reg === re2); // false
reg.foo = "baz";
console.log(re2.foo); // "bar"
To illustrate the above statements from the point of actual numbers, take a look at the performance difference between storedRegExp and inlineRegExp tests in this jsperf.
storedRegExp would be about 5 - 20% percent faster across browsers than inlineRegExp - the overhead of creating (and garbage collecting) a new RegExp object every time.
Conslusion:
If you're heavily using your literal regexps, consider caching them outside the scope where they are needed, so that they are not only be compiled once, but actual regexp objects for them would be created once as well.
There are two "regular expression" type objects in javascript.
Regular expression instances and the RegExp object.
Also, there are two ways to create regular expression instances:
using the /regex/ syntax and
using new RegExp('regex');
Each of these will create new regular expression instance each time.
However there is only ONE global RegExp object.
var input = 'abcdef';
var r1 = /(abc)/;
var r2 = /(def)/;
r1.exec(input);
alert(RegExp.$1); //outputs 'abc'
r2.exec(input);
alert(RegExp.$1); //outputs 'def'
The actual pattern is compiled as the script is loaded when you use Syntax 1
The pattern argument is compiled into an internal format before use. For Syntax 1, pattern is compiled as the script is loaded. For Syntax 2, pattern is compiled just before use, or when the compile method is called.
But you still could get different regular expression instances each method call. Test in chrome vs firefox
function testregex() {
var localreg = /abc/;
if (testregex.reg != null){
alert(localreg === testregex.reg);
};
testregex.reg = localreg;
}
testregex();
testregex();
It's VERY little overhead, but if you wanted exactly one regex, its safest to only create one instance outside of your function
The regex will be compiled every time you call the function if it's not in literal form.
Since you are including it in a literal form, you've got nothing to worry about.
Here's a quote from websina.com:
Regular expression literals provide compilation of the regular expression when the script is evaluated. When the regular expression will remain constant, use this for better performance.
Calling the constructor function of the RegExp object, as follows:
re = new RegExp("ab+c")
Using the constructor function provides runtime compilation of the regular expression. Use the constructor function when you know the regular expression pattern will be changing, or you don't know the pattern and are getting it from another source, such as user input.

Categories

Resources