When TeX is looking for a number it continues scanning tokens and expanding them until finding an unexpandable token that cannot be interpreted as a digit (in the already set radix, default decimal).
If this unexpandable token is a space token, it gets ignored (only one, though).
This means that with
\catcode`}=12}
the assignment has not yet been performed when the number is complete, and } has been tokenized with its current category code, that is, 2.
Always finish your constants with a space. Quoting the TeXbook:
For best results, always put a blank space after a numeric constant;
this blank space tells TeX that the constant is complete, and
such a space will never “get through” to the output. In fact, when you
don't have a blank space after a constant, TeX actually has to do
more work, because each constant continues until a non-digit has been
read; if this non-digit is not a space, TeX takes the token you did have
and backs it up, ready to be read again. (On the other hand, the author
often omits the space when a constant is immediately followed by some
other character, because extra spaces do look funny in the file;
aesthetics are more important than efficiency.)
This is different from other assignments:
\def\foo{1} % just for an example
\chardef\foo=12\foo
will not be equivalent to \chardef\foo=121, because in these cases TeX temporarily sets \foo as equivalent to \relax, until it can perform the assignment. So the second \foo stops the search for digits and no expansion of \foo will be done. On the other hand
\chardef\foo=12 \foo
works the same and is clearer.
\catcode`}=12 }\bye– cgnieder Jun 22 '17 at 09:02}try it with\tt– David Carlisle Jun 22 '17 at 09:07}. – David Carlisle Jun 22 '17 at 09:09