The Achilles Heel of JavaScript is its inconsistent behavior across implementations. It is virtually impossible to use it to do anything robust on the client side.
JavaScript is weakly typed, and the automatic coercions that it does can produce surprising results. "2" + "3" is "23" (+, when applied to two strings, performs concatenation); "2" * "3" is 6. (Multiplication not defined for strings; so the language tries converting them to numerals, succeeds, and multiplies those). This can be surprising.
Rather annoying gotcha in array constructor. new Array() produces empty array; new Array(2,3) produces array with 2 and 3 as its elements. new Array(5) does not produce array with 5 as its single element; instead, it returns a 5-element array!
Whereas most languages have one universal singular value (null/nil/Void/whatever); JavaScript has three - "false", "null" and "undefined". That leads to confusing and irregular semantics.
No integral types - the only numeric type supported is an IEEE754 double-precision float. For a scripting language, this limitation is probably less obnoxious than it would be elsewhere.
Language has LexicalScoping, but with an interesting twist. Unlike JavaScripts brethen C/C++/Java/C#/etc, where variables introduced in an anonymous block within a function are only valid within that block; in JavaScript such variables are valid for the entire function.
Every script is executed in a single global namespace that is accessible in browsers with the window object.
Automatic type conversion between strings and numbers, combined with '+' overloaded to mean concatenation and addition. This creates very counterintuitive effects if you accidentally convert a number to a string:
var i = 1;
// some code
i = i + ""; // oops!
// some more code
i + 1; // evaluates to the String '11'
i - 1; // evaluates to the Number 0
The automatic type conversion of the + function also leads to the intuitive effect that += 1 is different then the ++ operator:
var j = "1";
j++; // j becomes 2