That's true to an extent. Many important optimizations will be performed by the JIT compiler, but only as long as the programmer doesn't make it hard to do so! The JIT compiler has to meet a strict compromise to meet between itr execution time and the performance of the code it generates. Type inference (to optimize object accesses), escape analysis (to move allocations from heap to the stack and to optimize away closures), and other expensive interprocedural analyses are often not executed since the user might navigate to another website before they have paid off.
any tools to help analyze this type of thing (e.g. what is and is not optimal for the jit)? have heard the term deopt but not sure how to get visibility into that
The JVM can be instructed to emit diagnostics regarding JIT compilation. Dunno if similar things are possible with JavaScript engines. Apart from that, profiling. Coding style is being discussed to death in other comment threads here. In short, "boring code" (few closures and functional idioms, no reflection, careful use of dictionaries, no ultra-flexible function parameter lists, avoid regex unless absolutely required) avoids surprising (read: hard to optimize) behavior.
But maybe all of this is besides the point. It's unrealistic to do heavy duty processing in a dynamic language and expect that the JIT always saves us. In comparison, Python programmers suffer no illusions that their code is usually just "fast enough", and call out to external libraries when heavy duty processing is required. Modern browsers provide some of these optimized capabilities for JavaScript, and they should be used whenever possible.