Compilation of JavaScript code (usually cross-compilation from JavaScript to JavaScript) allows you to detect certain classes of error statically (i.e. without having to run the code) whereas JavaScript for the most part defers all such checks to runtime: this means that rarely executed parts of your script that use a variable incorrectly will only be detected if the code is ever executed. A compiler can detect many usages at compile time before the code is even deployed.
This kind of type checking is achieved by performing type inference: i.e. the compiler propagates known type information about a variable based on the point at which a variable's value is assigned throughout the program's various code paths and determines if the variable is used in a consistent fashion in other areas of the program. Obviously, due to the highly dynamic nature of JavaScript, this type inference is not perfect but it can still be useful.
JavaScript compilers can also perform minimization in order to reduce the size of a script to a minimum by renaming variables and method names etc. in order to minimize bandwidth usage as well as merge multiple scripts into a single file for ease of downloading.
- Google's Closure is an example of a JavaScript-to-JavaScript cross-compiler.
- Morfik produce another JavaScript-to-JavaScript cross-compiler which, I think, I predates Closure.
Philosophical Edit:
Compilers or cross-compilers that generate JavaScript as their target are effectively treating JavaScript as the "machine language" of the web browser and this is very similar in essence to compilers that emit C as a portable intermediate language. The line between preprocessor and compiler can be a grey one but I would suggest that something that tokenizes, parses and semantically analyses source code and emits some intermediate or machine language at the backend is more correctly considered a compiler than a preprocessor which usually performs only simple text substitution or macro expansion.