Every string has empty strings before and after each and every character.
Now, you are doing greedy matching with .*, which actually means "zero or more characters and match as much as possible". Here, Hello World! is matched by .* and then there is global modifier. So, it tries to match again and matches the empty string at the end (which matches because .* means zero or more characters). That is why you are getting it in the result.
You can confirm the same, with +, like this
var str = "Hello World!";
var reg = new RegExp(".+", "g");
console.log(str.match(reg));
// [ 'Hello World!' ]
Here, + means, one or more times. Since the .+ matches Hello World!, the global modifier searches again but found no more characters to match.
Want to see something interesting? Try this
var str = "Hello World!";
var reg = new RegExp(".*?", "g");
console.log(str.match(reg));
// [ '', '', '', '', '', '', '', '', '', '', '', '', '' ]
Why is that? .*? means match zero or more characters but match only as minimum as possible (non-greedy). So, it starts from the first character, finds an empty string closes the search. Global modifier makes the match again, finds another empty string after H, and so on, till the end of the string is reached.
But if you used +, like this
var str = "Hello World!";
var reg = new RegExp(".+?", "g");
console.log(str.match(reg));
// [ 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!' ]
It has to match one or more characters but match as minimum as possible. So, it matches one characters, stops. Global modifier matches again, matches the second character and so on.