views:

385

answers:

2

Please help me to understand why the following code works:

<script>
    var re = RegExp('\\ba\\b') ;
    alert(re.test('a')) ;
    alert(re.test('ab')) ;
</script>

In the first line there is no new operator.

As far as I know, a contructor in JavaScript is a function that initialize objects created by the operator new and they are not meant to return anything.

+15  A: 

In general, if something is documented as being a constructor, use new with it. But in this case, RegExp has a defined "factory" behavior for the situation where you've called it as a function instead. See Section 15.10.3 of the ECMAScript (JavaScript) specification (that links to the outgoing spec; the section number is the same in the new spec, which you can download from the ECMA front page [on the right-hand side]; I don't want to directly link to a ~4MB PDF file):

15.10.3 The RegExp Constructor Called as a Function
15.10.3.1 RegExp(pattern, flags)
If pattern is an object R whose [[Class]] property is "RegExp" and flags is undefined, then return R unchanged. Otherwise call the RegExp constructor (15.10.4.1), passing it the pattern and flags arguments and return the object constructed by that constructor.

You can actually define your own JavaScript constructor functions to allow omitting the new keyword (by detecting they've been called as a function instead, and turning around and calling themselves correctly), but I wouldn't suggest it as it leads to misleading code.

T.J. Crowder
Doing some more testing I see that behabior happens with all factory contructors (String, Date, etc.)
GetFree
But it's not a general rule. Most constructor functions I've seen not defined in the specification do not implement this custom factory feature.
T.J. Crowder
I see. Every factory constructor has its own behavior when it's called as a function. For instance, the Date contructor returns the date as a string (and not a Date object) when called as a function.
GetFree
Precisely. The only way to know what happens is to read the spec (or a derivative work that tries to be more accessible :-) ). And again, most constructors in the wild (not part of the spec) probably don't implement specific non-construction behaviors (unless they say they do!).
T.J. Crowder
I should say that the spec, though large (~242 pages) and written in fairly turgid prose, is actually pretty accessible once you get past (and get familiar with) the style.
T.J. Crowder
@GetFree, that's correct. The built-in constructors generally work when called as functions, but their behavior is different. For example, `String` converts values to native strings (not `String` objects), `Number` converts values to numbers (not `Number` objects), etc. `RegExp` is kind of a special case, because there is no other reasonable behavior.
Matthew Crumley
They behave like type casting (C++ style)
GetFree
+2  A: 

+1 TJ Crowder has it. The ECMAScript standard goes out of its way to define behaviours for the built-in constructor functions when called as plain functions. Often it simply calls itself back as a constructor, but there are some more complicated cases.

constructors in javascript [...] are not meant to return anything

In general, a constructor can ignore this and just return an independent object:

function Thing() {
    return {'foo': 1};
}

in this case you can equally use the function as a constructor (with new) or a plain function.

If the constructor doesn't return anything, as is the usual pattern for constructors, the new operator itself ensures that it returns the new object created and passed as this. In this case you must use new.

It's best not to rely on a constructor working as a bare function, and the alternative behaviours of the built-in constructors are rarely of any use, so generally you should stick with new.

bobince
Adding to what Bob said: The business of what happens when a constructor returns something is covered by the spec (Section 13.2.2). This allows, amongst other things, for singletons to be returned by constructors (which I wouldn't say is a *good* idea, but it's possible). Note that if you return something other than the object created for you by `new`, you may well be breaking `instanceof` and the prototype chain (unless, of course, you're turning another instance that was previously constructed, as in the singleton case). Basically, returning anything from a constructor is advanced usage. :-)
T.J. Crowder
+1. Just to add to "Bob" and "Teej" here, an explicit `return somethingOtherThan_this` is ignored if the value you return is a number, string, or boolean. In such cases the implicit `return this` silently overwrites your own return statement.
Crescent Fresh