That is what the g flag does. When you use it, exec will continue the next search from the end the previous match. But after your first match (a) there is nothing more left in the string, so you get an empty match. This empty match is usually used to terminate an exec-loop. If you know that there is only one match, remove the g (it means "global" search).
Note that you can (and should) get rid of those parentheses. They just cost you performance. Without them you will only get one a in the resulting array.
If you do want to consider multiple matches, but disregard that last empty match, use the loop technique:
var match;
while(match = r.exec(d))
// process match[0] here
Note that you only need this loop if you actually have (meaningful) capturing groups. If not (if you only want to get full matches), you can use match instead as elclanrs points out:
var matches = d.match(r);
EDIT:
I just realised, most of what I said is partially true but not the actual cause of ["", ""]. What really happens is this: the first time .* matches a. The second time the engine tries to continue the search after the previous match (after a). Since your pattern has .* (which mean 0 or more characters) it will now continue to match empty strings (because they match the pattern). And matching an empty string also does not advance the position for the next search. Hence, even with .match you will get ["a", ""] (match is clever enough to abort in such a case).
In fact, if you use that regex with the loop-technique you will get an endless loop (because match = ["", ""] will obviously not cause the loop to terminate). But in any case, you should realise that your pattern is nonsensical due to the *. It can match anything (including nothing). At least use .+. For whatever purpose.
null, after which the regex starts matching at the beginning again.*can always match. It will match an empty string, hencelastIndexwill not advance and the next search will start from that same position again. But.*can always match an empty string again. You will only ever getnull(after which the index is reset) if the pattern fails to match. But.*can by definition never fail (on anything).