Skip to content Skip to sidebar Skip to footer

Assigning Regexp.test To A Variable

The following code: var r = /^[0-9A-Z]$/.test; r('A') Throws 'TypeError: can't convert undefined to object' How else could I assign the test function to a variable, for passing in

Solution 1:

It has to do with the value of this inside the test method.

For example:

var obj = {
  method: function () { returnthis === obj }
};

obj.method(); // truevar method = obj.method;
method(); // false

If you call the test method "as a function" -as your example r();-, the this value will refer to undefined (for built-in or strict functions in ECMAScript 5, in the above example this will refer to the global object).

Calling any method of RegExp.prototype with a this value that is not a RegExp object, will always generate this TypeError exception, quoting the spec:

15.10.6 Properties of the RegExp Prototype Object

In the following descriptions of functions that are properties of the RegExp prototype object, the phrase “this RegExp object” refers to the object that is the this value for the invocation of the function; a TypeError exception is thrown if the this value is not an object or an object for which the value of the [[Class]] internal property is not "RegExp".

However you could bind the test method to your r function, using the Function.prototype.bind method:

var re = /^[0-9A-Z]$/,
    r = re.test.bind(re);

r("A"); // true

Or using call or apply:

var r = re.test;
r.call(re, "A"); // true

Solution 2:

As I've been essentially trying to answer this question in all my comments, let's summarize everything we've covered so far in an actual answer.

When you do this:

var r = /^[0-9A-Z]$/.test;

you are assigning the method named test from the RegExp object to the variable named r. It is just a method assignment. There is no connection whatsoever with the specific regular expression object that you created. If fact, r == RegExp.prototype.test.

When you then try this line of code:

r("A")

you are trying to execute RegExp.prototype.test and passing it "A", but you have no appropriate object context. When the test function runs, the this pointer won't point to a regular expression object, it will point to the global object (which in a browser is the window object).

In your o, a and b code example, it works because all you're doing is calling functions that refer to no instance data and the this pointer is not used at all (therefore it doesn't matter that it's not set to an appropriate object context). That isn't the case with the regular expression method. It needs its instance data (e.g. it's this pointer to point to a real regular expression object).

It is possible to take a method point and add the appropriate this pointer, though I have no idea why that would be useful in this particular example. For example, you could do this:

var re = /^[0-9A-Z]$/;
var r = re.test;
r.call(re);

That sets the this pointer to your regular expression object and then executes the r method with that this pointer.

I don't really know why you'd want to do that, but hopefully that helps explain things.

Solution 3:

MAJOR EDIT: Now that I've seen your update, which removed the problem my original post talked about, I realise that the problem is the test function needs to be associated to an object when it runs. Standard dot notation after a regex object will automatically set this within test equal to that object. When you call it by itself as r("A"); then this will be set to the window object, which doesn't work and gives an error. (This wouldn't matter for some functions, but test needs its this object to be a regex to operate on.)

You can make it work by explicitly setting the this using .call():

var re = /^[0-9A-Z]$/;
var rf = re.test;

alert(rf.call(re,"A"));     // displays 'true'alert(rf.call(/blah/,"A")); // displays 'false'

But that seems pretty silly. I'd ask why you can't just do this:

var r = /^[0-9A-Z]$/;
r.test("A");
r.test("B");

This lets you keep one copy of the regex, and you don't need your own function wrapper. If you really want the r("A") syntax just add a wrapper.

Post a Comment for "Assigning Regexp.test To A Variable"