Primitive Data Types, Arrays, Loops, and Conditions - Object-Oriented JavaScript Second Edition (2013)

Object-Oriented JavaScript Second Edition (2013)

Chapter 2. Primitive Data Types, Arrays, Loops, and Conditions

Before diving into the object-oriented features of JavaScript, let's first take a look at some of the basics. This chapter walks you through the following:

· The primitive data types in JavaScript, such as strings and numbers

· Arrays

· Common operators, such as +, -, delete, and typeof

· Flow control statements, such as loops and if-else conditions

Variables

Variables are used to store data; they are placeholders for concrete values. When writing programs, it's convenient to use variables instead of the actual data, as it's much easier to write pi instead of 3.141592653589793, especially when it happens several times inside your program. The data stored in a variable can be changed after it was initially assigned, hence the name "variable". You can also use variables to store data that is unknown to you while you write the code, such as the result of a later operation.

Using a variable requires two steps. You need to:

· Declare the variable

· Initialize it, that is, give it a value

To declare a variable, you use the var statement, like this:

var a;

var thisIsAVariable;

var _and_this_too;

var mix12three;

For the names of the variables, you can use any combination of letters, numbers, the underscore character, and the dollar sign. However, you can't start with a number, which means that this is invalid:

var 2three4five;

To initialize a variable means to give it a value for the first (initial) time. You have two ways to do so:

· Declare the variable first, then initialize it

· Declare and initialize it with a single statement

An example of the latter is:

var a = 1;

Now the variable named a contains the value 1.

You can declare (and optionally initialize) several variables with a single var statement; just separate the declarations with a comma:

var v1, v2, v3 = 'hello', v4 = 4, v5;

For readability, this is often written using one variable per line:

var v1,

v2,

v3 = 'hello',

v4 = 4,

v5;

Tip

The $ character in variable names

You may see the dollar sign character ($) used in variable names, as in $myvar or less commonly my$var. This character is allowed to appear anywhere in a variable name, although previous versions of the ECMA standard discouraged its use in handwritten programs and suggested it should only be used in generated code (programs written by other programs). This suggestion is not well respected by the JavaScript community, and $ is in fact commonly used in practice as a function name.

Variables are case sensitive

Variable names are case sensitive. You can easily verify this statement using your JavaScript console. Try typing this, pressing Enter after each line:

var case_matters = 'lower';

var CASE_MATTERS = 'upper';

case_matters;

CASE_MATTER;

To save keystrokes, when you enter the third line, you can type case and press the Tab key (or right-arrow key). The console autocompletes the variable name to case_matters. Similarly, for the last line, type CASE and press Tab. The end result is shown in the following figure:

Variables are case sensitive

Throughout the rest of this book, only the code for the examples is given instead of a screenshot, like so:

> var case_matters = 'lower';

> var CASE_MATTERS = 'upper';

> case_matters;

"lower"

> CASE_MATTERS;

"upper"

The greater-than signs (>) show the code that you type; the rest is the result as printed in the console. Again, remember that when you see such code examples, you're strongly encouraged to type in the code yourself. Then, you can experiment by tweaking it a little here and there to get a better feeling of how exactly it works.

Note

You can see in the screenshot that sometimes what you type in the console results in the word undefined. You can simply ignore this, but if you're curious, here's what happens: when evaluating (executing) what you type, the console prints the returned value. Some expressions (such as var a = 1;) don't return anything explicitly, in which case they implicitly return the special value undefined (more on it in a bit). When an expression returns some value (for example case_matters in the previous example or something such as 1 + 1), the resulting value is printed out. Not all consoles print the undefined value, for example the Firebug console.

Operators

Operators take one or two values (or variables), perform an operation, and return a value. Let's check out a simple example of using an operator, just to clarify the terminology:

> 1 + 2;

3

In this code:

· + is the operator

· The operation is addition

· The input values are 1 and 2 (the input values are also called operands)

· The result value is 3

· The whole thing is called an expression

Instead of using the values 1 and 2 directly in the expression, you can use variables. You can also use a variable to store the result of the operation, as the following example demonstrates:

> var a = 1;

> var b = 2;

> a + 1;

2

> b + 2;

4

> a + b;

3

> var c = a + b;

> c;

3

The following table lists the basic arithmetic operators:

Operator symbol

Operation

Example

+

Addition

> 1 + 2;

3

-

Subtraction

> 99.99 – 11;

88.99

*

Multiplication

> 2 * 3;

6

/

Division

> 6 / 4;

1.5

%

Modulo, the remainder of a division

> 6 % 3;

0

> 5 % 3;

2

It's sometimes useful to test if a number is even or odd. Using the modulo operator, it's easy to do just that. All odd numbers return 1 when divided by 2, while all even numbers return 0.

> 4 % 2;

0

> 5 % 2;

1

++

Increment a value by 1

Post-increment is when the input value is incremented after it's returned.

> var a = 123;

> var b = a++;

> b;

123

> a;

124

The opposite is pre-increment. The input value is incremented by 1 first and then returned.

> var a = 123;

> var b = ++a;

> b;

124

> a;

124

--

Decrement a value by 1

Post-decrement:

> var a = 123;

> var b = a--;

> b;

123

> a;

122

Pre-decrement:

> var a = 123;

> var b = --a;

> b;

122

> a;

122

var a = 1; is also an operation; it's the simple assignment operation, and = is the simple assignment operator.

There is also a family of operators that are a combination of an assignment and an arithmetic operator. These are called compound operators. They can make your code more compact. Let's see some of them with examples:

> var a = 5;

> a += 3;

8

In this example, a += 3; is just a shorter way of doing a = a + 3;:

> a -= 3;

5

Here, a -= 3; is the same as a = a - 3;.

Similarly:

> a *= 2;

10

> a /= 5;

2

> a %= 2;

0

In addition to the arithmetic and assignment operators discussed previously, there are other types of operators, as you'll see later in this and the following chapters.

Tip

Best practice

Always end your expressions with a semicolon. JavaScript has a semicolon insertion mechanism where it can add the semicolon if you forget it at the end of a line. However, this can also be a source of errors, so it's best to make sure you always explicitly state where you want to terminate your expressions. In other words, both expressions, > 1 + 1 and > 1 + 1;, will work; but, throughout the book you'll always see the second type, terminated with a semicolon, just to emphasize this habit.

Primitive data types

Any value that you use is of a certain type. In JavaScript, there are just a few primitive data types:

1. Number: This includes floating point numbers as well as integers. For example, these values are all numbers: 1, 100, 3.14.

2. String: These consist of any number of characters, for example "a", "one", and "one 2 three".

3. Boolean: This can be either true or false.

4. Undefined: When you try to access a variable that doesn't exist, you get the special value undefined. The same happens when you declare a variable without assigning a value to it yet. JavaScript initializes the variable behind the scenes with the valueundefined. The undefined data type can only have one value – the special value undefined.

5. Null: This is another special data type that can have only one value, namely the null value. It means no value, an empty value, or nothing. The difference with undefined is that if a variable has a value null, it's still defined, it just so happens that its value is nothing. You'll see some examples shortly.

Any value that doesn't belong to one of the five primitive types listed here is an object. Even null is considered an object, which is a little awkward—having an object (something) that is actually nothing. We'll learn more on objects in Chapter 4, Objects, but for the time being, just remember that in JavaScript the data types are either:

· Primitive (the five types listed previously)

· Non-primitive (objects)

Finding out the value type – the typeof operator

If you want to know the type of a variable or a value, you use the special typeof operator. This operator returns a string that represents the data type. The return values of using typeof are one of the following:

· "number"

· "string"

· "boolean"

· "undefined"

· "object"

· "function"

In the next few sections, you'll see typeof in action using examples of each of the five primitive data types.

Numbers

The simplest number is an integer. If you assign 1 to a variable and then use the typeof operator, it returns the string "number":

> var n = 1;

> typeof n;

"number"

> n = 1234;

> typeof n;

"number"

In the preceding example, you can see that the second time you set a variable's value, you don't need the var statement.

Numbers can also be floating point (decimals):

> var n2 = 1.23;

> typeof n;

"number"

You can call typeof directly on the value without assigning it to a variable first:

> typeof 123;

"number"

Octal and hexadecimal numbers

When a number starts with a 0, it's considered an octal number. For example, the octal 0377 is the decimal 255:

> var n3 = 0377;

> typeof n3;

"number"

> n3;

255

The last line in the preceding example prints the decimal representation of the octal value.

While you may not be intimately familiar with octal numbers, you've probably used hexadecimal values to define colors in CSS stylesheets.

In CSS, you have several options to define a color, two of them being:

· Using decimal values to specify the amount of R (red), G (green), and B (blue) ranging from 0 to 255. For example, rgb(0, 0, 0) is black and rgb(255, 0, 0) is red (maximum amount of red and no green or blue).

· Using hexadecimals and specifying two characters for each R, G, and B value. For example, #000000 is black and #ff0000 is red. This is because ff is the hexadecimal value for 255.

In JavaScript, you put 0x before a hexadecimal value (also called hex for short):

> var n4 = 0x00;

> typeof n4;

"number"

> n4;

0

> var n5 = 0xff;

> typeof n5;

"number"> n5;

255

Exponent literals

1e1 (also written as 1e+1 or 1E1 or 1E+1) represents the number one with one zero after it, or in other words, 10. Similarly, 2e+3 means the number 2 with 3 zeros after it, or 2000:

> 1e1;

10

> 1e+1;

10

> 2e+3;

2000

> typeof 2e+3;

"number"

2e+3 means moving the decimal point three digits to the right of the number 2. There's also 2e-3, meaning you move the decimal point three digits to the left of the number 2:

Exponent literals

> 2e-3;

0.002

> 123.456E-3;

0.123456

> typeof 2e-3;

"number"

Infinity

There is a special value in JavaScript called Infinity. It represents a number too big for JavaScript to handle. Infinity is indeed a number, as typing typeof Infinity in the console will confirm. You can also quickly check that a number with 308 zeros is ok, but 309 zeros is too much. To be precise, the biggest number JavaScript can handle is 1.7976931348623157e+308, while the smallest is 5e-324.

> Infinity;

Infinity

> typeof Infinity;

"number"

> 1e309;

Infinity

> 1e308;

1e+308

Dividing by zero gives you infinity:

> var a = 6 / 0;

> a;

Infinity

Infinity is the biggest number (or rather a little bigger than the biggest), but how about the smallest? It's infinity with a minus sign in front of it; minus infinity:

> var i = -Infinity;

> i;

-Infinity

> typeof i;

"number"

Does this mean you can have something that's exactly twice as big as Infinity, from 0 up to infinity and then from 0 down to minus infinity? Well, not really. When you sum infinity and minus infinity, you don't get 0, but something that is called NaN (Not a Number):

> Infinity – Infinity;

NaN

> -Infinity + Infinity;

NaN

Any other arithmetic operation with Infinity as one of the operands gives you Infinity:

> Infinity – 20;

Infinity

> -Infinity * 3;

-Infinity

> Infinity / 2;

Infinity

> Infinity – 99999999999999999;

Infinity

NaN

What was this NaN in the previous example? It turns out that despite its name, "Not a Number", NaN is a special value that is also a number:

> typeof NaN;

"number"

> var a = NaN;

> a;

NaN

You get NaN when you try to perform an operation that assumes numbers, but the operation fails. For example, if you try to multiply 10 by the character "f", the result is NaN, because "f" is obviously not a valid operand for a multiplication:

> var a = 10 * "f";

> a;

NaN

NaN is contagious, so if you have even one NaN in your arithmetic operation, the whole result goes down the drain:

> 1 + 2 + NaN;

NaN

Strings

A string is a sequence of characters used to represent text. In JavaScript, any value placed between single or double quotes is considered a string. This means that 1 is a number, but "1" is a string. When used with strings, typeof returns the string "string":

> var s = "some characters";

> typeof s;

"string"

> var s = 'some characters and numbers 123 5.87';

> typeof s;

"string"

Here's an example of a number used in the string context:

> var s = '1';

> typeof s;

"string"

If you put nothing in quotes, it's still a string (an empty string):

> var s = ""; typeof s;

"string"

As you already know, when you use the plus sign with two numbers, this is the arithmetic addition operation. However, if you use the plus sign with strings, this is a string concatenation operation, and it returns the two strings glued together:

> var s1 = "web";

> var s2 = "site";

> var s = s1 + s2;

> s;

"website"

> typeof s;

"string"

The dual purpose of the + operator is a source of errors. Therefore, if you intend to concatenate strings, it's always best to make sure that all of the operands are strings. The same applies for addition; if you intend to add numbers, make sure the operands are numbers. You'll learn various ways to do so further in the chapter and the book.

String conversions

When you use a number-like string (for example "1") as an operand in an arithmetic operation, the string is converted to a number behind the scenes. This works for all arithmetic operations except addition, because of its ambiguity:

> var s = '1';

> s = 3 * s;

> typeof s;

"number"

> s;

3

> var s = '1';

> s++;

> typeof s;

"number"

> s;

2

A lazy way to convert any number-like string to a number is to multiply it by 1 (another way is to use a function called parseInt(), as you'll see in the next chapter):

> var s = "100"; typeof s;

"string"

> s = s * 1;

100

> typeof s;

"number"

If the conversion fails, you'll get NaN:

> var movie = '101 dalmatians';

> movie * 1;

NaN

You convert a string to a number by multiplying by 1. The opposite—converting anything to a string—can be done by concatenating it with an empty string:

> var n = 1;

> typeof n;

"number"

> n = "" + n;

"1"

> typeof n;

"string"

Special strings

There are also strings with special meanings, as listed in the following table:

String

Meaning

Example

\\

\'

\"

\ is the escape character.

When you want to have quotes inside your string, you escape them so that JavaScript doesn't think they mean the end of the string.

If you want to have an actual backslash in the string, escape it with another backslash.

> var s = 'I don't know';

This is an error, because JavaScript thinks the string is I don and the rest is invalid code. The following are valid:

· > var s = 'I don\'t know';

· > var s = "I don\'t know";

· > var s = "I don't know";

· > var s = '"Hello", he said.';

· > var s = "\"Hello\", he said.";

Escaping the escape:

> var s = "1\\2"; s;

"1\2"

\n

End of line.

> var s = '\n1\n2\n3\n';

> s;

"

1

2

3

"

\r

Carriage return.

Consider the following statements:

· > var s = '1\r2';

· > var s = '1\n\r2';

· > var s = '1\r\n2';

The result of all of these is:

> s;

"1

2"

\t

Tab.

> var s = "1\t2";

> s;

"1 2"

\u

\u followed by a character code allows you to use Unicode.

Here's my name in Bulgarian written with Cyrillic characters:

> "\u0421\u0442\u043E\u044F\u043D";

"Стoян"

There are also additional characters that are rarely used: \b (backspace), \v (vertical tab), and \f (form feed).

Booleans

There are only two values that belong to the Boolean data type: the values true and false, used without quotes:

> var b = true;

> typeof b;

"boolean"

> var b = false;

> typeof b;

"boolean"

If you quote true or false, they become strings:

> var b = "true";

> typeof b;

"string"

Logical operators

There are three operators, called logical operators, that work with Boolean values. These are:

· ! – logical NOT (negation)

· && – logical AND

· || – logical OR

You know that when something is not true, it must be false. Here's how this is expressed using JavaScript and the logical ! operator:

> var b = !true;

> b;

false

If you use the logical NOT twice, you get the original value:

> var b = !!true;

> b;

true

If you use a logical operator on a non-Boolean value, the value is converted to Boolean behind the scenes:

> var b = "one";

> !b;

false

In the preceding case, the string value "one" is converted to a Boolean, true, and then negated. The result of negating true is false. In the next example, there's a double negation, so the result is true:

> var b = "one";

> !!b;

true

You can convert any value to its Boolean equivalent using a double negation. Understanding how any value converts to a Boolean is important. Most values convert to true with the exception of the following, which convert to false:

· The empty string ""

· null

· undefined

· The number 0

· The number NaN

· The Boolean false

These six values are referred to as falsy, while all others are truthy (including, for example, the strings "0", " ", and "false").

Let's see some examples of the other two operators—the logical AND (&&) and the logical OR (||). When you use &&, the result is true only if all of the operands are true. When you use ||, the result is true if at least one of the operands is true:

> var b1 = true, b2 = false;

> b1 || b2;

true

> b1 && b2;

false

Here's a list of the possible operations and their results:

Operation

Result

true && true

true

true && false

false

false && true

false

false && false

false

true || true

true

true || false

true

false || true

true

false || false

false

You can use several logical operations one after the other:

> true && true && false && true;

false

> false || true || false;

true

You can also mix && and || in the same expression. In such cases, you should use parentheses to clarify how you intend the operation to work. Consider these:

> false && false || true && true;

true

> false && (false || true) && true;

false

Operator precedence

You might wonder why the previous expression (false && false || true && true) returned true. The answer lies in the operator precedence. As you know from mathematics:

> 1 + 2 * 3;

7

This is because multiplication has higher precedence over addition, so 2 * 3 is evaluated first, as if you typed:

> 1 + (2 * 3);

7

Similarly for logical operations, ! has the highest precedence and is executed first, assuming there are no parentheses that demand otherwise. Then, in the order of precedence, comes && and finally ||. In other words, the following two code snippets are the same:

> false && false || true && true;

true

and

> (false && false) || (true && true);

true

Tip

Best practice

Use parentheses instead of relying on operator precedence. This makes your code easier to read and understand.

The ECMAScript standard defines the precedence of operators. While it may be a good memorization exercise, this book doesn't offer it. First of all, you'll forget it, and second, even if you manage to remember it, you shouldn't rely on it. The person reading and maintaining your code will likely be confused.

Lazy evaluation

If you have several logical operations one after the other, but the result becomes clear at some point before the end, the final operations will not be performed because they don't affect the end result. Consider this:

> true || false || true || false || true;

true

Since these are all OR operations and have the same precedence, the result will be true if at least one of the operands is true. After the first operand is evaluated, it becomes clear that the result will be true, no matter what values follow. So, the JavaScript engine decides to be lazy (OK, efficient) and avoids unnecessary work by evaluating code that doesn't affect the end result. You can verify this short-circuiting behavior by experimenting in the console:

> var b = 5;

> true || (b = 6);

true

> b;

5

> true && (b = 6);

6

> b;

6

This example also shows another interesting 'margin-top:6.0pt;margin-right:29.0pt;margin-bottom: 6.0pt;margin-left:29.0pt;line-height:normal'>> true || "something";

true

> true && "something";

"something"

> true && "something" && true;

true

This behavior is not something you should rely on because it makes the code harder to understand. It's common to use this behavior to define variables when you're not sure whether they were previously defined. In the next example, if the variable mynumber is defined, its value is kept; otherwise, it's initialized with the value 10:

> var mynumber = mynumber || 10;

> mynumber;

10

This is simple and looks elegant, but be aware that it's not completely foolproof. If mynumber is defined and initialized to 0 (or to any of the six falsy values), this code might not behave as you expect:

> var mynumber = 0;

> var mynumber = mynumber || 10;

> mynumber;

10

Comparison

There's another set of operators that all return a Boolean value as a result of the operation. These are the comparison operators. The following table lists them together with example uses:

Operator symbol

Description

Example

==

Equality comparison: Returns true when both operands are equal. The operands are converted to the same type before being compared. Also called loose comparison.

> 1 == 1;

true

> 1 == 2;

false

> 1 == '1';

true

===

Equality and type comparison: Returns true if both operands are equal and of the same type. It's better and safer to compare this way because there's no behind-the-scenes type conversions. It is also called strict comparison.

> 1 === '1';

false

> 1 === 1;

true

!=

Non-equality comparison: Returns true if the operands are not equal to each other (after a type conversion).

> 1 != 1;

false

> 1 != '1';

false

> 1 != '2';

true

!==

Non-equality comparison without type conversion: Returns true if the operands are not equal or if they are of different types.

> 1 !== 1;

false

> 1 !== '1';

true

>

Returns true if the left operand is greater than the right one.

> 1 > 1;

false

> 33 > 22;

true

>=

Returns true if the left operand is greater than or equal to the right one.

> 1 >= 1;

true

<

Returns true if the left operand is less than the right one.

> 1 < 1;

false

> 1 < 2;

true

<=

Returns true if the left operand is less than or equal to the right one.

> 1 <= 1;

true

> 1 <= 2;

true

Note that NaN is not equal to anything, not even itself:

> NaN == NaN;

false

Undefined and null

If you try to use a non-existing variable, you'll get an error:

> foo;

ReferenceError: foo is not defined

Using the typeof operator on a non-existing variable is not an error. You get the string "undefined" back:

> typeof foo;

"undefined"

If you declare a variable without giving it a value, this is, of course, not an error. But, the typeof still returns "undefined":

> var somevar;

> somevar;

> typeof somevar;

"undefined"

This is because when you declare a variable without initializing it, JavaScript automatically initializes it with the value undefined:

> var somevar;

> somevar === undefined;

true

The null value, on the other hand, is not assigned by JavaScript behind the scenes; it's assigned by your code:

> var somevar = null;

null

> somevar;

null

> typeof somevar;

"object"

Although the difference between null and undefined is small, it could be critical at times. For example, if you attempt an arithmetic operation, you get different results:

> var i = 1 + undefined;

> i;

NaN

> var i = 1 + null;

> i;

1

This is because of the different ways null and undefined are converted to the other primitive types. The following examples show the possible conversions:

· Conversion to a number:

· > 1 * undefined;

· NaN

· > 1 * null;

· 0

· Conversion to a Boolean:

· > !!undefined;

· false

· > !!null;

· false

· Conversion to a string:

· > "value: " + null;

· "value: null"

· > "value: " + undefined;

· "value: undefined"

Primitive data types recap

Let's quickly summarize some of the main points discussed so far:

· There are five primitive data types in JavaScript:

· Number

· String

· Boolean

· Undefined

· Null

· Everything that is not a primitive data type is an object

· The primitive number data type can store positive and negative integers or floats, hexadecimal numbers, octal numbers, exponents, and the special numbers NaN, Infinity, and –Infinity

· The string data type contains characters in quotes

· The only values of the Boolean data type are true and false

· The only value of the null data type is the value null

· The only value of the undefined data type is the value undefined

· All values become true when converted to a Boolean, with the exception of the six falsy values:

· ""

· null

· undefined

· 0

· NaN

· false

Arrays

Now that you know about the basic primitive data types in JavaScript, it's time to move to a more powerful data structure—the array.

So, what is an array? It's simply a list (a sequence) of values. Instead of using one variable to store one value, you can use one array variable to store any number of values as elements of the array.

To declare a variable that contains an empty array, you use square brackets with nothing between them:

> var a = [];

To define an array that has three elements, you do this:

> var a = [1, 2, 3];

When you simply type the name of the array in the console, you get the contents of your array:

> a;

[1, 2, 3]

Now the question is how to access the values stored in these array elements. The elements contained in an array are indexed with consecutive numbers starting from zero. The first element has index (or position) 0, the second has index 1, and so on. Here's the three-element array from the previous example:

Index

Value

0

1

1

2

2

3

To access an array element, you specify the index of that element inside square brackets. So, a[0] gives you the first element of the array a, a[1] gives you the second, and so on:

> a[0];

1

> a[1];

2

Adding/updating array elements

Using the index, you can also update the values of the elements of the array. The next example updates the third element (index 2) and prints the contents of the new array:

> a[2] = 'three';

"three"

> a;

[1, 2, "three"]

You can add more elements by addressing an index that didn't exist before:

> a[3] = 'four';

"four"

> a;

[1, 2, "three", "four"]

If you add a new element, but leave a gap in the array, those elements in between don't exist and return the undefined value if accessed. Check out this example:

> var a = [1, 2, 3];

> a[6] = 'new';

"new"

> a;

[1, 2, 3, undefined x 3, "new"]

Deleting elements

To delete an element, you use the delete operator. However, after the deletion, the length of the array does not change. In a sense, you get a hole in the array:

> var a = [1, 2, 3];

> delete a[1];

true

> a;

[1, undefined, 3]

> typeof a[1];

"undefined"

Arrays of arrays

Arrays can contain all types of values, including other arrays:

> var a = [1, "two", false, null, undefined];

> a;

[1, "two", false, null, undefined]

> a[5] = [1, 2, 3];

[1, 2, 3]

> a;

[1, "two", false, null, undefined, Array[3]]

The Array[3] in the result is clickable in the console and it expands the array values. Let's see an example where you have an array of two elements, both of them being other arrays:

> var a = [[1, 2, 3], [4, 5, 6]];

> a;

[Array[3], Array[3]]

The first element of the array is a[0], and it's also an array:

> a[0];

[1, 2, 3]

To access an element in the nested array, you refer to the element index in another set of square brackets:

> a[0][0];

1

> a[1][2];

6

Note that you can use the array notation to access individual characters inside a string:

> var s = 'one';

> s[0];

"o"

> s[1];

"n"

> s[2];

"e"

Note

Array access to strings has been supported by many browsers for a while (not older IEs), but has been officially recognized only as late as ECMAScript 5.

There are more ways to have fun with arrays (and you'll get to those in Chapter 4, Objects), but let's stop here for now, remembering that:

· An array is a data store

· An array contains indexed elements

· Indexes start from zero and increment by one for each element in the array

· To access an element of an array, you use its index in square brackets

· An array can contain any type of data, including other arrays

Conditions and loops

Conditions provide a simple but powerful way to control the flow of code execution. Loops allow you to perform repetitive operations with less code. Let's take a look at:

· if conditions

· switch statements

· while, do-while, for, and for-in loops

Note

The examples in the following sections require you to switch to the multiline Firebug console. Or, if you use the WebKit console, use Shift + Enter instead of Enter to add a new line.

The if condition

Here's a simple example of an if condition:

var result = '', a = 3;

if (a > 2) {

result = 'a is greater than 2';

}

The parts of the if condition are:

· The if statement

· A condition in parentheses—"is a greater than 2?"

· A block of code wrapped in {} that executes if the condition is satisfied

The condition (the part in parentheses) always returns a Boolean value, and may also contain the following:

· A logical operation: !, &&, or ||

· A comparison, such as ===, !=, >, and so on

· Any value or variable that can be converted to a Boolean

· A combination of the above

The else clause

There can also be an optional else part of the if condition. The else statement is followed by a block of code that runs if the condition evaluates to false:

if (a > 2) {

result = 'a is greater than 2';

} else {

result = 'a is NOT greater than 2';

}

In between the if and the else, there can also be an unlimited number of else if conditions. Here's an example:

if (a > 2 || a < -2) {

result = 'a is not between -2 and 2';

} else if (a === 0 && b === 0) {

result = 'both a and b are zeros';

} else if (a === b) {

result = 'a and b are equal';

} else {

result = 'I give up';

}

You can also nest conditions by putting new conditions within any of the blocks:

if (a === 1) {

if (b === 2) {

result = 'a is 1 and b is 2';

} else {

result = 'a is 1 but b is definitely not 2';

}

} else {

result = 'a is not 1, no idea about b';

}

Code blocks

In the preceding examples, you saw the use of code blocks. Let's take a moment to clarify what a block of code is, because you use blocks extensively when constructing conditions and loops.

A block of code consists of zero or more expressions enclosed in curly brackets:

{

var a = 1;

var b = 3;

}

You can nest blocks within each other indefinitely:

{

var a = 1;

var b = 3;

var c, d;

{

c = a + b;

{

d = a - b;

}

}

}

Tip

Best practice tips

· Use end-of-line semicolons, as discussed previously in the chapter. Although the semicolon is optional when you have only one expression per line, it's good to develop the habit of using them. For best readability, the individual expressions inside a block should be placed one per line and separated by semicolons.

· Indent any code placed within curly brackets. Some programmers like one tab indentation, some use four spaces, and some use two spaces. It really doesn't matter, as long as you're consistent. In the preceding example, the outer block is indented with two spaces, the code in the first nested block is indented with four spaces, and the innermost block is indented with six spaces.

· Use curly brackets. When a block consists of only one expression, the curly brackets are optional, but for readability and maintainability, you should get into the habit of always using them, even when they're optional.

Checking if a variable exists

Let's apply the new knowledge about conditions for something practical. It's often necessary to check whether a variable exists. The laziest way to do this is to simply put the variable in the condition part of the if, for example, if (somevar) {...}. But, this is not necessarily the best method. Let's take a look at an example that tests whether a variable called somevar exists, and if so, sets the result variable to yes:

> var result = '';

> if (somevar) {

result = 'yes';

}

ReferenceError: somevar is not defined

> result;

""

This code obviously works because the end result was not "yes". But firstly, the code generated an error: somevar is not defined, and you don't want your code to behave like that. Secondly, just because if (somevar) returns false doesn't mean that somevar is not defined. It could be that somevar is defined and initialized but contains a falsy value like false or 0.

A better way to check if a variable is defined is to use typeof:

> var result = "";

> if (typeof somevar !== "undefined") {

result = "yes";

}

> result;

""

typeof always returns a string, and you can compare this string with the string "undefined". Note that the variable somevar may have been declared but not assigned a value yet, and you'll still get the same result. So, when testing with typeof like this, you're really testing whether the variable has any value other than the value undefined:

> var somevar;

> if (typeof somevar !== "undefined") {

result = "yes";

}

> result;

""

> somevar = undefined;

> if (typeof somevar !== "undefined") {

result = "yes";

}

> result;

""

If a variable is defined and initialized with any value other than undefined, its type returned by typeof is no longer "undefined":

> somevar = 123;

> if (typeof somevar !== "undefined") {

result = 'yes';

}

> result;

"yes"

Alternative if syntax

When you have a simple condition, you can consider using an alternative if syntax. Take a look at this:

var a = 1;

var result = '';

if (a === 1) {

result = "a is one";

} else {

result = "a is not one";

}

You can also write this as:

> var a = 1;

> var result = (a === 1) ? "a is one" : "a is not one";

You should only use this syntax for simple conditions. Be careful not to abuse it, as it can easily make your code unreadable. Here's an example.

Let's say you want to make sure a number is within a certain range, say between 50 and 100:

> var a = 123;

> a = a > 100 ? 100 : a < 50 ? 50: a;

> a;

100

It may not be clear how this code works exactly because of the multiple ?. Adding parentheses makes it a little clearer:

> var a = 123;

> a = (a > 100 ? 100 : a < 50) ? 50 : a;

> a;

50

> var a = 123;

> a = a > 100 ? 100 : (a < 50 ? 50 : a);

> a;

100

?: is called a ternary operator because it takes three operands.

Switch

If you find yourself using an if condition and having too many else if parts, you could consider changing the if to a switch:

var a = '1',

result = '';

switch (a) {

case 1:

result = 'Number 1';

break;

case '1':

result = 'String 1';

break;

default:

result = 'I don\'t know';

break;

}

The result after executing this is "String 1". Let's see what the parts of a switch are:

· The switch statement.

· An expression in parentheses. The expression most often contains a variable, but can be anything that returns a value.

· A number of case blocks enclosed in curly brackets.

· Each case statement is followed by an expression. The result of the expression is compared to the expression found after the switch statement. If the result of the comparison is true, the code that follows the colon after the case is executed.

· There is an optional break statement to signal the end of the case block. If this break statement is reached, the switch is all done. Otherwise, if the break is missing, the program execution enters the next case block.

· There's an optional default case marked with the default statement and followed by a block of code. The default case is executed if none of the previous cases evaluated to true.

In other words, the step-by-step procedure for executing a switch statement is as follows:

1. Evaluate the switch expression found in parentheses; remember it.

2. Move to the first case and compare its value with the one from step 1.

3. If the comparison in step 2 returns true, execute the code in the case block.

4. After the case block is executed, if there's a break statement at the end of it, exit the switch.

5. If there's no break or step 2 returned false, move on to the next case block.

6. Repeat steps 2 to 5.

7. If you are still here (no exit in step 4), execute the code following the default statement.

Tip

Best practice tips

· Indent the code that follows the case lines. You can also indent case from the switch, but that doesn't give you much in terms of readability.

· Don't forget to break.

· Sometimes, you may want to omit the break intentionally, but that's rare. It's called a fall-through and should always be documented because it may look like an accidental omission. On the other hand, sometimes you may want to omit the whole code block following a case and have two cases sharing the same code. This is fine, but doesn't change the rule that if there's code that follows a case statement, this code should end with a break. In terms of indentation, aligning the break with the case or with the code inside the case is a personal preference; again, being consistent is what matters.

· Use the default case. This helps you make sure you always have a meaningful result after the switch statement, even if none of the cases matches the value being switched.

Loops

The if-else and switch statements allow your code to take different paths, as if you're at a crossroad and decide which way to go depending on a condition. Loops, on the other hand, allow your code to take a few roundabouts before merging back into the main road. How many repetitions? That depends on the result of evaluating a condition before (or after) each iteration.

Let's say you are (your program execution is) traveling from A to B. At some point, you reach a place where you evaluate a condition, C. The result of evaluating C tells you if you should go into a loop, L. You make one iteration and arrive at C again. Then, you evaluate the condition once again to see if another iteration is needed. Eventually, you move on your way to B.

Loops

An infinite loop is when the condition is always true and your code gets stuck in the loop "forever". This is, of course, a logical error, and you should look out for such scenarios.

In JavaScript, there are four types of loops:

· while loops

· do-while loops

· for loops

· for-in loops

While loops

while loops are the simplest type of iteration. They look like this:

var i = 0;

while (i < 10) {

i++;

}

The while statement is followed by a condition in parentheses and a code block in curly brackets. As long as the condition evaluates to true, the code block is executed over and over again.

Do-while loops

do-while loops are a slight variation of while loops. An example is shown as follows:

var i = 0;

do {

i++;

} while (i < 10);

Here, the do statement is followed by a code block and a condition after the block. This means that the code block is always executed, at least once, before the condition is evaluated.

If you initialize i to 11 instead of 0 in the last two examples, the code block in the first example (the while loop) will not be executed, and i will still be 11 at the end, while in the second (the do-while loop), the code block will be executed once and i will become 12.

For loops

for is the most widely used type of loop, and you should make sure you're comfortable with this one. It requires just a little bit more in terms of syntax.

For loops

In addition to the condition C and the code block L, you have the following:

· Initialization—code that is executed before you even enter the loop (marked with 0 in the diagram)

· Increment—code that is executed after every iteration (marked with ++ in the diagram)

The most widely used for loop pattern is:

· In the initialization part, you define a variable (or set the initial value of an existing variable), most often called i

· In the condition part, you compare i to a boundary value, like i < 100

· In the increment part, you increase i by 1, like i++

Here's an example:

var punishment = '';

for (var i = 0; i < 100; i++) {

punishment += 'I will never do this again, ';

}

All three parts (initialization, condition, and increment) can contain multiple expressions separated by commas. Say you want to rewrite the example and define the variable punishment inside the initialization part of the loop:

for (var i = 0, punishment = ''; i < 100; i++) {

punishment += 'I will never do this again, ';

}

Can you move the body of the loop inside the increment part? Yes, you can, especially as it's a one-liner. This gives you a loop that looks a little awkward, as it has no body. Note that this is just an intellectual exercise; it's not recommended that you write awkward-looking code:

for (

var i = 0, punishment = '';

i < 100;

i++, punishment += 'I will never do this again, ') {

// nothing here

}

These three parts are all optional. Here's another way of rewriting the same example:

var i = 0, punishment = '';

for (;;) {

punishment += 'I will never do this again, ';

if (++i == 100) {

break;

}

}

Although the last rewrite works exactly the same way as the original, it's longer and harder to read. It's also possible to achieve the same result by using a while loop. But, for loops make the code tighter and more robust because the mere syntax of the for loop makes you think about the three parts (initialization, condition, and increment), and thus helps you reconfirm your logic and avoid situations such as being stuck in an infinite loop.

The for loops can be nested within each other. Here's an example of a loop that is nested inside another loop and assembles a string containing 10 rows and 10 columns of asterisks. Think of i being the row and j being the column of an "image":

var res = '\n';

for (var i = 0; i < 10; i++) {

for (var j = 0; j < 10; j++) {

res += '* ';

}

res += '\n';

}

The result is a string like the following:

"

* * * * * * * * * *

* * * * * * * * * *

* * * * * * * * * *

* * * * * * * * * *

* * * * * * * * * *

* * * * * * * * * *

* * * * * * * * * *

* * * * * * * * * *

* * * * * * * * * *

* * * * * * * * * *

"

Here's another example that uses nested loops and a modulo operation to draw a snowflake-like result:

var res = '\n', i, j;

for (i = 1; i <= 7; i++) {

for (j = 1; j <= 15; j++) {

res += (i * j) % 8 ? ' ' : '*';

}

res += '\n';

}

The result is:

"

*

* * *

*

* * * * * * *

*

* * *

*

"

For-in loops

The for-in loop is used to iterate over the elements of an array (or an object, as you'll see later). This is its only use; it cannot be used as a general-purpose repetition mechanism that replaces for or while. Let's see an example of using a for-in to loop through the elements of an array. But, bear in mind that this is for informational purposes only, as for-in is mostly suitable for objects, and the regular for loop should be used for arrays.

In this example, you iterate over all of the elements of an array and print out the index (the key) and the value of each element:

// example for information only

// for-in loops are used for objects

// regular for is better suited for arrays

var a = ['a', 'b', 'c', 'x', 'y', 'z'];

var result = '\n';

for (var i in a) {

result += 'index: ' + i + ', value: ' + a[i] + '\n';

}

The result is:

"

index: 0, value: a

index: 1, value: b

index: 2, value: c

index: 3, value: x

index: 4, value: y

index: 5, value: z

"

Comments

One last thing for this chapter: comments. Inside your JavaScript program, you can put comments. These are ignored by the JavaScript engine and don't have any effect on how the program works. But, they can be invaluable when you revisit your code after a few months, or transfer the code to someone else for maintenance.

Two types of comments are allowed:

· Single line comments start with // and end at the end of the line.

· Multiline comments start with /* and end with */ on the same line or any subsequent line. Note that any code in between the comment start and the comment end is ignored.

Some examples are as follows:

// beginning of line

var a = 1; // anywhere on the line

/* multi-line comment on a single line */

/*

comment that spans several lines

*/

There are even utilities, such as JSDoc and YUIDoc, that can parse your code and extract meaningful documentation based on your comments.

Summary

In this chapter, you learned a lot about the basic building blocks of a JavaScript program. Now you know the primitive data types:

· Number

· String

· Boolean

· Undefined

· Null

You also know quite a few operators:

· Arithmetic operators: +, -, *, /, and %

· Increment operators: ++ and --

· Assignment operators: =, +=, -=, *=, /=, and %=

· Special operators: typeof and delete

· Logical operators: &&, ||, and !

· Comparison operators: ==, ===, !=, !==, <, >, >=, and <=

· The ternary operator ?:

Then, you learned how to use arrays to store and access data, and finally you saw different ways to control the flow of your program—using conditions (if-else or switch) and loops (while, do-while, for, and for-in).

This is quite a bit of information; now take a moment to go through the exercises below, then give yourself a well-deserved pat on the back before diving into the next chapter. More fun is coming up!

Exercises

1. What is the result of executing each of these lines in the console? Why?

2. > var a; typeof a;

3. > var s = '1s'; s++;

4. > !!"false";

5. > !!undefined;

6. > typeof -Infinity;

7. > 10 % "0";

8. > undefined == null;

9. > false === "";

10.> typeof "2E+2";

> a = 3e+3; a++;

11. What is the value of v after the following?

> var v = v || 10;

Experiment by first setting v to 100, 0, or null.

12. Write a small program that prints out the multiplication table. Hint: use a loop nested inside another loop.