Javascript
Quirks and tips about Javascript.
== vs ===
== and != comparisons will compare the boolean representation of an expression instead of the value itself. === and !== do actual compares on the values of the objects themselves. Example:
0 === "" //false
Because of this it's almost always better to use ===, it's most likely what you thought you were doing with == anyway.
&& and ||
&& and || don't actually return booleans (like true and false). They return one of the expressions that were actually compared depending on the expressions used. For &&, it returns the 1st expression if it's false, otherwise it returns the 2nd expression. For ||, it returns the 1st expression if it's true, otherwise it returns the 2nd expression. Example:
(0 && "cat") //returns 0
("dog" || "cat") //returns "dog"
(0 || "cat") //returns "cat"
This is because of how JS evaluates. (x && y) is false if x is false. It doesn't evaluate y. (x || y) is true if x is true. It doesn't evaluate y. So JS basically returns the last thing it "looks at" and uses its boolean representation for the compare result.
parseInt() Woes
Always pass in the radix (base) when using parseInt(). This is because strings starting with 0 will be translated into octal, not decimal. Since you never really know what string may be passed, this makes sure it comes out in decimal. Example:
parseInt("08"); //0
parseInt("08", 10); //8
Unary Number Conversions
There's another way to parse ints (or floats) that can be even easier. You can use unary number conversion. Example:
(+"08"); //8
(-"09"); //-9
(-"10.21"); //-10.21
Note however that any letters in the string will output NaN
, so use with caution. Spaces however will not screw up the conversion, which makes this good when grabbing table data. Also, the parens are not required here but they are good practice. Otherwise it's easy to confuse the unary operators for ++ or --.
var x = (+"07") + (+"08");
The second example is much more readable, and less prone to error.
Incorrect Floats
Floats in JS end up wrong when doing math on them. For example:
There isn't much you can do about this. You certainly can't compare floats for this reason. You can write some methods to work around this but you will have to know the precision of the floats in order to do so. A general algorithm would look something like:
This would be good to two decimal places and produce the correct result. The other option is to always use ints, making math easy, and then simply convert to decimal form for display only.
eval() is Bad
eval() takes a string and evaluates it to some functional code. Slow, sloppy, and never needed. Most eval's are used to do dot sytntax with a variable string. It's not needed because you can do the same with arrays (they're equivalent). Example:
object.method[myString]; //same thing, faster, and easier to read
setTimeout() also can take a string as an argument. This string is sent through eval(), so it's just as bad and not needed. You can use an anonymous function instead (also works on setInterval() as well):
setTimeout(function () { //same thing, faster, and easier to read
myFunction(myVar);
}, 1000);
var and Scoping
var will not "reset" a variable. Example:
var x; //x is still 5
JS has function level scoping only. But var can play a role in variable scoping because var is not actually required to declare a variable. Variables declared without var are global regardless of where they are declared. Example:
y = 2; //global
function myFunc() {
var x = 3; //local to function, x is 3;
alert(x); //will show 3
z = 4; //z is now global outside of function scope
}
myFunc();
alert(x); //will show 1, not 3
alert(z); //will show 4 (will throw error if myFunc() wasn't called)
It's important to use var in functions because otherwise you can easily clobber global vars defined elsewhere without realizing it. As such it's better to define local vars as the first lines in a function (even if they have no value) as opposed to later in the function. Because JS doesn't have block level scoping, this will be easier to read for anyone coming from a language like C.
new is Overused
Using new to create new objects is slow and generally unnecessary. Only use new if you have to. The same thing can usually be done with much simpler methods. Example:
var myArray = [];
var myObject = {};
typeof() Bugs
typeof() is used to determine what type of object you're working with. Unfortunately it's not always accurate:
typeof({}); //"object" - correct
typeof([]); //"object" - WRONG (should be "array")
typeof(""); //"string" - correct
typeof(true); //"boolean" - correct
typeof(null); //"object" - WRONG (should be "null")
typeof(Function); //"function" - correct
typeof(undefined); //"undefined" - correct
It is possible to write your own typeof() method to fix this, but it is not trivial.
Automatic Semicolon Insertion
JS will auto insert semicolons if you forget to put them in. This can reek havoc on your code. Example:
name: "myName" //semicolon inserted after }, returns name object
}
return
{
name: "myName" //semicolon inserted after return, returns nothing
}
In the 1st example, JS will auto insert a semicolon after the } bracket. This works as intended. In the 2nd example JS will auto insert a semicolon after the word return since the { is on a separate line. Thus it returns undefined, not the object. Make sure you put semicolons after every statement so JS doesn't auto insert wrongly for you. This is also a good reason to put { brackets on the same line as the statement that precedes it, instead of on a new line as some people do.
Reserved Words
The following are reserved words. Don't use them as properties, methods or variables, as you will throw up conflicts. Pick a different word. Also notice, most of these words aren't even used in JS. Alas, they're still reserved and are off limits.
abstract, boolean, break, byte, case, catch, char, class, const, continue, debugger, default, delete, do, double, else, enum, export, extends, false, final, finally, float, for, function, goto, if, implements, import, in, instanceof, int, interface, long, native, new, null, package, private, protected, public, return, short, static, super, switch, synchronized, this, throw, throws, transient, true, try, typeof, var, void, volatile, while, with