Matt has answered why. I just wanted to add that you can see this by checking the value of lastIndex on the RegExp object before and after the exec call
var reg = new RegExp('#([a-f0-9]{3})$', 'gi');
for (var i = 0; i < 10; i++) {
console.log(reg.lastIndex);
console.log(reg.exec('#fff'));
console.log(reg.lastIndex);
}
output is
0
["#fff", "fff"]
4
4
null
0
0
["#fff", "fff"]
4
4
null
0
0
["#fff", "fff"]
4
4
null
0
0
["#fff", "fff"]
4
4
null
0
0
["#fff", "fff"]
4
4
null
0
undefined
demonstrating that on every other iteration of the loop, the regex matching is starting from where the lastIndex finished. You could set lastIndex to 0 before each exec call or drop the flag altogether.