the language denoted by a regular expression
A regular expression is just a string of symbols on the page, like a recipe written down. The language it denotes is the actual set of strings that recipe produces, like the dish you get from following it. We write L(R) for 'the language denoted by R'. Keeping the formula and its meaning separate is the key to thinking clearly about regular expressions.
L(R) is defined inductively, following the structure of R from the atoms outward. The base cases set L(a) = { a } for a symbol a, L(ε) = { ε }, and L(∅) = { }. The inductive cases then say: L(R+S) = L(R) ∪ L(S) (union of the two languages), L(RS) = L(R) concatenated with L(S) (every string of R followed by every string of S), and L(R*) = the Kleene star of L(R) (zero or more concatenated copies). To find what any expression means, you apply these rules from the inside out. For example, L((a+b)c) first builds L(a+b) = { a, b }, then concatenates each with c to get { ac, bc }.
This inductive definition is what makes regular expressions precise mathematics rather than vague pattern-talk. It also explains a subtle point: two different-looking expressions can denote the same language. For instance a* and (a*)* both denote { ε, a, aa, ... }, even though the strings of symbols differ. Two expressions are called equivalent when they denote the same language, and proving such equivalences is exactly what the algebraic identities are for.
Decode (0+1)*00 step by step: L(0+1) = { 0, 1 }, so L((0+1)*) is all binary strings, then concatenating 00 forces the ending. Thus L((0+1)*00) is every binary string that ends in 00.
Meaning is computed from the expression's structure, inside out.
An expression (a string of symbols) and the language it denotes (a set of strings) are different things; different expressions can denote the same language, and that is exactly when we call them equivalent.