Why is “asdf”.replace(/.*/g, “x”) == “xx”?

As per the ECMA-262 standard, String.prototype.replace calls RegExp.prototype[@@replace], which says:

11. Repeat, while done is false
  a. Let result be ? RegExpExec(rx, S).
  b. If result is null, set done to true.
  c. Else result is not null,
    i. Append result to the end of results.
    ii. If global is false, set done to true.
    iii. Else,
      1. Let matchStr be ? ToString(? Get(result, "0")).
      2. If matchStr is the empty String, then
        a. Let thisIndex be ? ToLength(? Get(rx, "lastIndex")).
        b. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode).
        c. Perform ? Set(rx, "lastIndex", nextIndex, true).

where rx is /.*/g and S is 'asdf'.

See 11.c.iii.2.b:

b. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode).

Therefore in 'asdf'.replace(/.*/g, 'x') it is actually:

  1. result (undefined), results = [], lastIndex = 0
  2. result = 'asdf', results = [ 'asdf' ], lastIndex = 4
  3. result = '', results = [ 'asdf', '' ], lastIndex = 4, AdvanceStringIndex, set lastIndex to 5
  4. result = null, results = [ 'asdf', '' ], return

Therefore there are 2 matches.

Leave a Comment