David K.
David K.

Reputation: 6361

difference between 'var a = 2' and 'this.a = 2'

I just discovered the weirdest bug in some javascript code dealing with RegExp.test. I had a regular expression regexp declared inside a function and I had a closure that had a reference to regexp and I was using the closure to iterate over an array of strings to test them with the help of collect from prototype.js, i.e.

function some_func() {
  var regexp = /regular_expression/;
  an_array_of_strings.collect(
     function(str) {
       if (regexp.test(str)) {
         do_something();
       }
     }
  );
}

The really weird thing was that calling regexp.test(str) inside the closure would alternate between true and false on the same input. I looked at the source for RegExp.test and I didn't see anything fishy but there was something going on because how can the same string pass and fail the same regular expression. After staring some more at RegExp.test I basically concluded that variables declared in RegExp.test were continuing to exist between invocations and were messing up subsequent invocations. So here's the question: What is the difference between

this.a = 2;

and

var a = 2;

when the above statements appear inside a method being called on an object inside a closure that holds a reference to that object? I'm asking because the bug disappears when I move regexp.test outside the closure. When regexp.test is called outside the closure then it doesn't flip-flop between true and false on each call. I have no idea why this is happening.

Edit: When I was moving the regexp outside the closure I was forgetting to add the global option so that's why the bug was disappearing. Thanks Ivo.

Upvotes: 2

Views: 943

Answers (3)

Ivo Wetzel
Ivo Wetzel

Reputation: 46735

Since you didn't show your RegExp but I just answered something similar to this, I suppose that you're using the global option in your RegExp, which has some interesting side effects.

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.

Source: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/RegExp/test

So what exactly happens here is that since you're using the global option for the regex, it will continue to search the string after it found an match.

regexp.test("d")

This will find d at position 0.

regexp.test("d")

This will now search for d starting at position 1, but since that's the end of the string it will not find anything therefore returning false.

We can use the lastIndex property of the regex to proof that:

regexp.lastIndex
>> 0
regexp.test("d")
>> true
regexp.lastIndex
>> 1
regexp.test("d")
>> false

So to solve the issue you need to remove the global option from your RegExp.

Disclaimer, this is a copy of my previous answer:
Unusual javascript Regex result, explanation please!

Upvotes: 3

LaustN
LaustN

Reputation: 720

Have a look at this page about the wonders of this in JS. The meaning of this changes quite dramatically, depending on how you use your functions.

Upvotes: 1

Lentonator
Lentonator

Reputation: 86

This is a tricky question, as at first glance they appear to be identical.

I would surmise that this.a is owned by the function, but may also extend for the life of that function, not just the function call itself; whereas var a would be created and destroyed each time the function is executed.

Upvotes: 1

Related Questions