Round brackets do two jobs at once: they group, so a quantifier or an alternation applies to everything inside, and they capture, so you can read that part back afterwards.
Groups are numbered by their opening bracket, left to right, nesting included. ((a)(b)) has three groups: the outer is 1, the a is 2, the b is 3.
(?:…) groups without capturing. Use it whenever you only wanted the grouping — it keeps the numbers of the groups after it from shifting when you add one, which is how a pattern edited in a hurry starts returning the wrong field.
(?<name>…) captures and names. The group still has its number; the name is an alias, and a much better one to depend on.
A group can give two answers that look the same on a screen and are not: it matched the empty string, or it never ran at all. (b)? against a gives you nothing — no value, not an empty one. (b*) against a gives you an empty string.
In JavaScript the first is undefined and the second is "", and code that treats them alike is code that has not decided what an absent field means.