var keyword, followed by the variable identifier. To initialize a variable, you assign a value to it using the assignment operator (
=). As in other languages, the result of the assignment operator is the assigned value, so you can chain them.
Variables that are declared but not initialized are
undefined. I’ll talk about the
undefined value a little later.
var x = "Hello, world!"; x = 5;
typeof operator. This operator returns a string representation of the type. I’ll specify what those strings actually are as the need arises.
long), signed and unsigned numbers, or integer and floating-point numbers.
Numeric literals can use decimal notation (
1.555), exponential notation (
3.14159E-27), and hex notation (
0x5FF). Most interpreters support octal notation (
0775), but it’s not standardized, so it should be avoided.
Infinitynumeric value, which (surprise!) represents positive infinity. It has a negated version, so
-Infinityrepresents negative infinity. These values work exactly like you would expect if you were a mathematician, but programmers may not be used to them. If you divide any non-zero number by zero (+0 or -0), you get either
-Infinity. When you divide zero by zero, you instead get
NaN(which I discuss below). When you try to subtract
Infinityfrom itself, you also get
- A Boolean type can only be
chartype, just a
All primitive types behave like value types. This means that they are copied upon assignment, are passed and returned by value, and that equality operators compare their contents (and not their memory locations). This is exactly how primitive types behave in other programming languages, so I won’t go into detail here.
typeof on a primitive type will return a string with that type’s name: “number”, “boolean”, or “string”.
“None” values and types: undefined, null, and NaN
Most computer languages have one specific value that means “no value.” What it is called varies by language: C uses zero or
NULL, C++11 uses
nullptr, Java uses
null, Lisp uses
nil, Python uses
None, and so forth.
- This is the most common “none” value. A variable is
undefinedwhen it is declared, but no value was ever assigned to it. A function that does not return any explicit value will return
undefined. You also get
undefinedwhen you attempt to use a property or method of an object, and no such property or method exists. Note, however, that accessing an undeclared variable will usually cause a
ReferenceError, not return an undefined value. (In most cases, an “undeclared variable” is really just a typo.)
undefinedliteral represents both a value and a primitive type. Using
typeofon a variable with the value
undefined, as well as on the
undefinedvalue itself, will return “undefined”.
nullvalue; uninitialized variables are
nullliteral represents both a value and a primitive type, but unlike
undefined, the value does not have itself as its type. Using
typeofon a variable whose value is
"null". However, Using
nullitself will return “object”. Just go with it.
- This stands for “Not a Number.” You usually get this because you tried to convert something to a
numbertype, and it can’t be converted. It is also the result if you divide zero by zero, or if you subtract
Infinityfrom itself. Note that this value is commutative: using any numeric operator with
NaNwill result in
Unlike the other two values,
NaNis not a type. Using
typeofon a variable with the value
NaN, as well as on
NaNitself, will return “number”. It is a special value, in that it is not equal to itself. To test if a variable has the value
NaN, you need to use the
isNaN()function. I’ll talk about this later.
Primitive Type Coercion
When other types are coerced into the
- If it’s a
trueevaluates to 1, and
falseevaluates to 0. This is about as straightforward as we’re going to get.
- If it’s a
NaN. Remember that
NaNis commutative, so any further numeric operations will also result in
- If it’s
null, it evaluates to zero.
- If it’s
undefined, it cannot be evaluated as a
numberat all; the result will be
- If it’s an object, that object is first converted to a primitive value (by implicitly calling the
valueOf()method). Then, that primitive value is coerced to a number using the rules above. (For most objects, this will result in
+, +=, -, -=, /, /=, *, *=, >, >=, <, or
<=. But there are two huge “gotchas,” both involving strings.
string and a
number to a
string, not the other way around. Thus
0 + "1" will yield
"01", not the number 1.
This also applies to the addition assignment operator:
+=. On the other hand, the unary addition operator does not do string concatenation. So,
0 + +"1" will yield the number 1.
The second “gotcha” is that the relational operators also operate on strings – but only if both sides of the operator are string types. If that’s the case, then it does a lexicographical comparison of the strings, and returns true or false depending upon the operator. This is essentially the same thing C++ does to overload the relational operators for
number types, and then compare them.
When other types are coerced into the
string type, the result is generally a human-readable form of the value. So, for example, if the type is a
number and its value is 3.14159, then the resulting string will be “3.14159”. Converting
boolean types will result in “true” or “false” depending upon the value.
What is not quite as straightforward is what happens when the “none types” are coerced. The result is actually their value as a string: “NaN”, “undefined”, or “null”. This may be unexpected, especially from people coming from other languages, who expect those values to be coerced to the empty string.
Speaking of which, a quick-and-dirty way to convert anything to a
string is just to concatenate it with the empty string:
> x = "" + null; "null"
do/while loop, or
for loop. It also happens when you use any of the logical operators:
==, !=, !, &&, or
These are the six falsy values:
- “” (the empty string)
- 0 (the number zero)
- -0 (the number negative zero)
Unfortunately, there are a lot of “gotcha” rules when using the
== (equality) and
!= (inequality) operators:
nullare not considered equal to any other falsy value except themselves:
> false == null; false > false == undefined; false > null == undefined; true
NaNis never considered equal to any other value, not even itself:
> false == NaN; false > NaN == NaN; false
This is why you need to use the
isNaN()function to test if a variable has the sepcial
- A string that contains only whitespace will evaluate to false, unless it is compared with another string:
> false == " \t\n"; true > false == " "; true > " \t\n" == 0; true > " \t\n" == " "; false
Making matters worse, these “gotchas” only happen when you use the equality operators. The other Boolean operators behave exactly as expected:
> if (" " && " \t\n") true; else false; true > if (" " && "") true; else false; false
This is because the equality operators follow The Abstract Equality Comparison Algorithm from the ECMAScript specification.
=== (strict equality) and
!== (strict inequality) operators. These operators follow the Strict Equality Comparison Algorithm. They do not do any type coercion at all, so two expressions will be equivalent only if they are exactly the same value and type.
As a general rule, you should always use the strict equality operators instead of their non-strict versions.
Any variable that refers to any kind of object will be an object type. Object types behave like reference types in other languages: they are not copied upon assignment, are passed and returned by reference, and equality operators compare their memory locations (not their values).
Generally speaking, using
typeof on an object type will simply return
typeof on a function name will return
Objects have members, which can either be properties (data) or methods (functions). The members of an object are (usually) accessed by the “dot operator,” more formally the member access operator: a single period between the object on the left, and its member on the right. Objects inherit all of the members of its prototype, so all objects (even functions) inherit all of the methods of Object.prototype. The most useful methods are toString() and valueOf().
Both objects and functions are big topics, so I won’t go into any great detail here. Each will get extensive coverage later in the article. But it is necessary to know about objects in general in order to understand wrappers and regular expressions.
Wrapper Objects and Wrapper Functions
A wrapper object is an object that represents a primitive type, and has methods that do useful operations on those types. With the exception of the “none” types (
undefined), each primitive type has a corresponding function that can construct a wrapper object. For reference, they are Number, Boolean, and String.
Wrapper objects are usually temporary objects that are created when you apply a method to a primitive type. For example, the
String object has a convenient method called
trim(), which trims the whitespace from the beginning and end of a string, and returns the new string. You can use this method on a string literal, like so:
> " Hello, world! ".trim(); "Hello, world!"
String object out of the
" Hello, world! " literal; invokes the
trim() method on that object, returning the result; then destroys the temporary object. (Or, at least, it behaves as if it does; how it actually accomplishes this is not specified in the standard.)
This also works for variables that represent primitive types. You can invoke the
trim() method on a variable that represents a primitive
string, and the type of the variable won’t change. In fact, this is probably how you’ll use autoboxing 99% of the time.
Wrappers can also be used to convert between types. Say that you want to convert a
number to a
string. You could use the
Number function to do so:
> x = "3.1415"; "3.1415" > typeof x; "string" > x = Number(x); 3.1415 > typeof x; "number"
new keyword to construct objects using functions as constructors. If you put the
new keyword before one of the wrapper functions, you’ll create an object, and not a primitive type.
This is very confusing, completely unnecessary, and can have a pretty severe performance impact. So, don’t do it. Just use autoboxing instead.
Regular Expression Objects
RegExp objects with their own literal syntax.
To create a
RegExp literal, you put a pattern between two forward slashes, followed by optional modifiers. It is also possible to create an object using the
RegExp() constructor, passing in the pattern string as the first argument, and a modifier string as the second. Here’s an example of both:
// RegExp literal var r = /^[a-z_$][\w$_]*$/i; // Using the RegExp function var r = new RegExp("^[a-z_$][\w$_]*$", "i");
Generally speaking, it is preferable to use the literal syntax, because it has much better performance. The only time you should use the constructor is when your regular expression pattern is only known at runtime (for example, it comes from user input).
- i: performs case-Insensitive matching
- g: performs Global matching (finds all matches, not just the first)
- m: performs Multiline matching
These modifiers are essentially flags, so they can be combined without issue.
Once you have a
RegExp object, you can test that object against a
string. There are two useful methods to do this. The
test() method simply returns
true if there is a match, and
false otherwise. The
exec() method returns the first occurrence of the match (as a string object), or
null if no match is found.
String object also has methods that accept
RegExp objects as parameters:
split(). In fact, it is probably more common to use these methods than it is to use the