JavaScript has been around almost as long as web browsers themselves. It first appeared in 1995 with Netscape Navigator 2.0 and is the only programming language supported by all the most popular browsers. As a result, if you want to build dynamic websites, you need to know JavaScript.
For a long time, JavaScript was dismissed as a second-rate language, only appropriate for implementing basic functionality such as field validation. In the last five years, JavaScript's reputation has improved dramatically. This happened partly as a result of the massive performance increases that have occurred with JavaScript engines, beginning in Chrome and rippling out to all the other major browsers. More important, however, programmers began to re-evaluate the language itself and learned to harness its power.
Although JavaScript contains more than its fair share of idiosyncrasies, and although the designers of the language made some unusual decisions, JavaScript turns out to be a powerful and flexible language when it is used correctly. The goal of the next few lessons is to not only introduce the language, but also to offer some advice on how you should use the language if you want to write large and complex web applications.
This lesson will provide a quick introduction to the data types and syntax of JavaScript. These aspects of the language are reasonably conventional and are easy to pick up for anyone with a background in other programming languages.
In this lesson, you will write JavaScript directly in the Chrome JavaScript console. In order to use this, open the contacts.html
web page from Lesson 8, and open the development tools using:
Once the development tools are open, click the Console tab. This provides a command prompt for writing JavaScript and allows you to directly manipulate the current web page. In order to see this, type the equation 1 + 1
at the command prompt. This should display the result immediately, as shown in Figure 11.1.
Pressing Enter always executes the statement in the console; therefore, if you need to write code that spans more than one line, hold down the Shift key when you press Enter.
In the sections that follow I will insert a > to show I am writing code into the console. You should omit this when you write the same code. Additionally, I will show the response on the next line if appropriate. For instance:
> 1 + 1
2
You will start your look at JavaScript by examining the different types it uses to represent data.
Character strings in JavaScript can be surrounded by either single or double quotes. To see an example, type the following into the console:
> "Welcome to JavaScript"
This is referred to as a string literal because the statement evaluates to the string itself. It is of course possible to assign a string to a variable. For instance:
> s1 = "Welcome to JavaScript";
The variable s1
now refers to this string, and if you type s1
at the console, the string will be printed. Additionally, you can ask JavaScript what data type the variable has:
> typeof s1;
"string"
It is also possible to perform operations on a string. Technically these are called methods, as you will see when you look at objects in Lesson 14. In order to see the available methods, simply type s1.
in the console; the autocomplete feature will then show the available methods (see Figure 11.2).
This book is not a reference book so I will not you walk through the entire API, but the following methods are the most commonly used methods on strings:
toUpperCase
: Convert text to uppercase.toLowerCase
: Convert text to lowercase.substr
: Extract a portion of the string using a starting and (optional) ending index. For instance, s1.substr(0, 7)
returns Welcome
. Counting always starts at 0.indexOf
: Returns the first index of a provided string inside the string; for instance, s1.indexOf('e')
returns 1
. Counting in JavaScript always starts at 0, so the second character is at position 1.length
: This is a property of the string rather than a method; therefore, you do not use brackets when invoking it. For instance, s1.length
returns 21.replace
: This method replaces the first occurrence of one string for the new one provided. For instance, s1.replace('e', ‘E')
returns “WElcome to JavaScript”
.It is also possible to append text to an existing string using the + operator. If you execute the following, a new string will be returned that concatenates the two strings:
> s1 + " - Let's get started";
If, however, you look at the value of s1
after executing this, you will see it has retained its old value:
> s1;
"Welcome to JavaScript"
Once a string has been assigned a value, it can never be modified (it is immutable). Any time an operation appears to modify a string, a new string is actually created. Therefore, to update the value of s1
you need to assign the result of the expression to it:
> s1 = s1 + " - Let's get started";
Finally, if you need to use special characters inside a string, you can prepend a backslash to it. For instance, the next example contains a ‘ character inside a quoted string so I use a backslash before it:
s2 = 'This is Dane's code';
Of course, in this case I could have simply wrapped the string inside double quotes because the quote character would have no special meaning in such a string:
s2 = "This is Dane's code";
JavaScript uses a single numeric type for all numbers, including decimals: All numbers are technically 64-bit floating-point numbers.
Variables can be assigned numeric values as follows:
> n1 = 200;
> n2 = 2.432432432;
The typeof
operator will confirm these are numbers:
> typeof n1
"number"
JavaScript then supports all the common mathematical operators for manipulating numbers. For example:
> n1 / 2
100
> n1 * (200 + n2);
40486.486486400005
For more advanced operations, JavaScript also provides a library called Math
that is modeled on the same library in Java. For instance:
> Math.pow(3,2)
9
> Math.round(n2)
2
JavaScript also supports three special numeric values. These are numbers, but they cannot be represented as conventional numbers:
Number.POSITIVE_INFINITY
: This value is created when a positive number is divided by 0. Although you may have been taught that numbers cannot be divided by 0, because all numbers are floating-point in JavaScript, the language assumes that the number 0 could be a tiny, but still non-zero, number that cannot be represented in 64 bits of memory. If you divide a number by such a tiny number, the result will approach infinity.Number.NEGATIVE_INFINITY
: This is returned when a negative number is divided by 0.NaN
: This stands for not-a-number, but confusingly, it is still a number. This value is created when operations on numbers return values that cannot be represented as numbers. For instance: 1 / “hello”
or Math.sqrt(-1)
. It is possible to check for this value using a special JavaScript function: isNaN(Math.sqrt(-1))
.Booleans are used to capture the values true
and false
. For instance:
> b1 = true;
> b2 = false;
Boolean values are commonly returned by logical operations. For instance:
> 10 > 5
true
Before looking at what null
is, it is worth looking at variables in slightly more detail. When you execute a statement such as this:
> n1 = 200;
the variable n1
takes on the data type of number
. The variable n1
is not intrinsically linked to numbers, however; you can change its type by assigning it a new value:
> n1 = "Testing";
Another way of looking at this is that the variable n1
starts out by referring to the number 200
, and then it is changed to refer to the string “Testing”
. You can therefore also change n1
so that it refers to nothing at all:
> n1 = null;
null
therefore means the absence of a value. JavaScript has a small quirk with null
values:
> typeof n1
"object"
This is a historic bug in the language itself: Despite this, null
is a distinct data type in JavaScript.
The value of undefined
is returned if you access a variable, or a property on an object, that does not exist. For instance, if you type the following at the command line, the value of undefined
will be returned:
> typeof n3
"undefined"
Arrays are not technically a distinct data type; they are a type of object, but it is still worth introducing them in this section.
An array contains zero or more elements of any data type. You can declare an array as follows:
a1 = [];
The initial elements in the array can also be provided as a comma separated list inside the square brackets:
a1 = [1,2,3,4];
You do not need to declare the size of the array; you can simply start inserting elements, and it will expand to support them:
a1[2] = 20;
a1[1] = "hello"
Because arrays are objects, they also support methods; for instance, this will add a new element at the end of the array.
a1.push(200);
while this will sort the array:
a1.sort()
You can access elements in the array by specifying their position inside the square brackets:
> a1[1]
"hello"
The lessons ahead will make extensive use of arrays, and many additional features will be introduced.
All other values in JavaScript are objects. You will spend a lot of time looking at these over the next few lessons so I will not discuss them here.
Functions are the basic building blocks of many JavaScript applications. A function in JavaScript accepts zero or more parameters, executes a series of statements, and then optionally returns a value.
You can create a function as follows (remember to hold down the Shift key when entering a new line into the console; you may also decide to copy and paste the code from a text editor):
function doubleTheNumber(num) {
var result = num * 2;
return result;
}
In this example, you are creating a function called doubleTheNumber
and have stated that it accepts a single parameter called num
.
In the body of the function you then multiply num
by 2 and store the result in a local variable called result
. Finally, on the last line of the function you return this variable. The curly brackets denote the code block relating to the function.
You can then execute this function as follows:
> doubleTheNumber(9);
18
Notice that the variable result
is declared with the var
keyword. This means that the variable is local to the function, and is automatically destroyed when the function ends. The var
keyword can be omitted, and the function will still work. To prove this, change the function as follows:
function doubleTheNumber(num) {
result = num * 2;
return result;
}
If you execute this, it will continue to work as expected:
> doubleTheNumber(10);
20
The overall outcome is not the same, however. The variable result
has been created as a global variable, and will exist even after the function has finished executing. You can see this by executing the following:
> result;
20
Using global variables is dangerous and should be kept to a minimum because there is always the possibly that two independent blocks of code will accidentally use the same variable name.
You will return to look at functions in substantially more detail in Lesson 13.
JavaScript includes a standard set of control structures for looping and branching. These will be familiar to anyone with a programming background because they use the same basic syntax as those in Java, C#, and Python (among others).
It is possible to perform looping with either a for
loop or a while
loop. The following example uses a for
loop to add the contents of an array together:
> a1 = [3,6,4,1,4,9]
> var result = 0;
> for (var i = 0; i < a1.length; i++) {
result = result + a1[i];
}
> result
27
The for
loop consists of three distinct portions:
i
is declared to act as the counter; this is initially set to the value 0.i
is less than the length of the array (6).i
should have its value increased by 1 (i++
) each time the loop completes a cycle.The loop also uses curly brackets to denote its scope so each time the loop executes, the following statement will be executed:
result = result + a1[i];
Because the first index of an array is 0, the first iteration will therefore set the result
variable to 3, and so on, until all the elements in the array have been evaluated.
If you would like to see more details as the loop executes, you can add console.log
statements to print logging information to the console. For instance:
for (var i = 0; i < a1.length; i++) {
console.log('The value of i is ' + i);
console.log('The value in the array is ' + a1[i]);
result = result + a1[i];
}
The second main loop variant is the while
loop. While
loops evaluate an expression with each iteration. While this is true, they keep iterating through the loop; if it is ever false the loop ceases. For instance:
var result = 0;
var counter = 0;
while (counter < a1.length) {
result = result + a1[counter];
counter++;
}
result;
You will notice that this still initializes a counter variable to 0 and increments its value with each iteration, but these are done before the loop starts and inside the loop respectively, not in the loop declaration.
JavaScript supports break
and continue
statements to control loop execution. I will introduce these along with the next subject: control structures. The following function accepts two parameters: an array of positive numbers, and a number. It then adds together all the even numbers in the array and returns true
if this sums to more than the number passed as an argument to the second parameter:
function checkCountEven(a1, n1) {
var result = false;
var count = 0;
for (var i = 0; i < a1.length; i++) {
var number = a1[i];
if (number % 2 != 0) {
continue;
}
count = count + number;
if (count > n1) {
result = true;
break;
}
}
return result;
}
You can call this as follows:
> a1 = [3, 6, 4, 1, 4, 9]
> checkCountEven(a1, 20)
false
This function starts by declaring two local variables and then starts looping through the array using a for
loop.
Inside the for
loop, you start by extracting the number from the array for the position you are at. You then check whether this is an odd number using the expression number % 2 != 0
. This expression literally states “return true if the remainder of dividing the number by 2 is not 0”. If this is true, the if
block executes.
If the statement returns true
, you do not want to count the number so you use the continue
keyword to skip immediately to the next loop iteration.
If the number is even, you add it to the result and then check to see whether the running total is greater than the number passed in using another if
statement. If this evaluates to true
, you know that the overall result must be true
, and therefore you do not need to check any more numbers in the loop. You therefore use the break
keyword to jump out of the loop immediately, and the function simply returns its result
.
Conditional expressions can also support if else
and else
statements. For instance:
function describeNumber(num) {
if (num >= 0 && num % 2 == 0) {
console.log(num + ' is a positive even number'),
} else if (num >= 0 && num % 2 == 1) {
console.log(num + ' is a positive odd number'),
} else if (num < 0 && num % 2 == 0) {
console.log(num + ' is a negative even number'),
} else {
console.log(num + ' is a negative odd number'),
}
}
Notice in this example that you combine multiple Boolean expressions with the and (&&
) operator. When this is used, the entire expression returns true
only if both sub-expressions are true.
JavaScript also supports a switch statement and a ternary operator for performing conditional logic. Although these will not be introduced, they work in a manner familiar to anyone who has used them in other languages.
One unique aspect of JavaScript is that every value and every expression evaluates to either true
or false
. To see this in action, create the following function:
function whatAmI(v1) {
if (v1) {
console.log('I am true'),
} else {
console.log('I am false'),
}
}
Notice that because values evaluate to true
or false
, you can simply state if (v1)
to determine if the argument passed in is true. You can now call this with a variety of values:
> whatAmI("hello")
I am true
> whatAmI("")
I am false
> whatAmI(22)
I am true
> whatAmI(null)
I am false
> whatAmI(8 + 9)
I am true
There are some surprising results here. The following are not true:
false
0
(zero)””
(empty string)null
undefined
NaN
(this value is neither true or false, which is why the isNaN
function is needed to detect it)All other values evaluate to true
.
You can actually simplify this function down to a single line as follows:
function whatAmI(v1) {
console.log('I am '+ !!v1);
}
!
is the not operator so if it is applied to any variable, it returns the opposite of its Boolean value. You can then negate this with an additional !
operator to return its actual truthy value.
JavaScript code makes extensive use of the fact that values are either true or false in if
statements. For instance, if you only want to print the string held in s1 if it has a value, you can use the following:
if (s1) {
console.log(s1);
}
JavaScript is a dynamically typed language. This means that the types of variables are only determined at runtime. Although dynamically typed languages are very flexible in many ways, they are also prone to bugs when types are not as expected. Consider a function such as this:
function add(n1, n2) {
return n1+n2;
}
This function operates as expected when called with two numbers, but what happens if you invoke this as follows?
> add(1, '0')
In this case, the result is the string value 10
. This may or may not be what you were expecting.
In a statically typed language, you would declare that n1
and n2
were numbers and refuse to allow it to be invoked with strings. This is not possible in JavaScript.
This is made slightly worse due to the fact that JavaScript is very forgiving. Consider the following examples:
> add(1, [])
"1"
> add(1, true)
2
JavaScript does have its own internal logic to explain these results, but they are seldom intuitive or expected. In order to circumvent issues such as this, it is common to write functions so that they generate errors if they are passed unexpected data types. For instance:
function add(v1, v2) {
if (typeof v1 === "number"
&& typeof v2 === "number") {
return v1+v2;
} else {
throw "both arguments must be numbers";
}
}
Notice the throw
statement in this example: This will generate an error to the caller, as shown in Figure 11.3.
This is still not as explicit as a compile time error, but at least it ensures that, if the program fails, it is obvious why it has failed.
In this Try It, you will use the techniques you have learned in this lesson to write two utility functions. If you get stuck on either of these examples, you may want to watch the screencast, which will walk through both examples. Completed versions of both functions are available on the book's website.
You will use the Chrome console for these examples. It is, however, recommended that you write the code in a text editor and copy the completed versions into the Chrome console.
The first utility function you will create will accept a single parameter, which should be a string, and will return the reverse of the string: If it is passed “Hello,” it will return “olleH.”
reverse
and declare that it accepts a single parameter.for
loop. You will need to initialize a counter variable with an initial value of 0, and loop while this is less than the length of the string.charAt
method to extract a character at a given position.Once the function is complete, you should be able to call it as follows:
> reverse("Hello");
"olleH"
The second utility function will accept an array of numbers, and return true
if the sum of all the positive numbers is greater than the sum of the absolute value of all the negative numbers.
calculateSums
, and declare that it accepts a single parameter, which in this case will be an array.while
loop in this example so you also need to create a counter variable and initialize it to 0.while
loop, and add curly brackets for its code block. The while
loop should test that the counter is less than the length of the array.Math.abs()
and add the result to the sum of negative numbers.while
loop will run forever: This is called an infinite loop.It should be possible to call the function as follows:
> calculateSums([-1,2])
true
> calculateSums([-1,2,-3])
false
3.133.123.34