Chapter 7: Dynamic Data on the World-Wide Web
7.1 Programming the Web with JavaScript
JavaScript is a programming language that works with the text, HTML, and CSS of a Web page. It was introduced in 1995, long after the first Web servers appeared in 1991.
JavaScript is based on the C programming language, a characteristic it shares with other programming languages such as Java and C’s superset C++, and they will therefore appear similar to each other. Like Java and C++, JavaScript is object-oriented, though it has slightly more restricted capabilities.
“JavaScript” is actually a product name of Netscape Communications Corporation, whose Navigator Web browser evolved into Mozilla Firefox. It was originally named LiveScript but was renamed because of the popularity of the Java language. Variants include JScript from Microsoft and ActionScript from Adobe. It has been standardized by the European Computer Manufacturers Association (ECMA) and is officially known as ECMAScript.
The Mozilla Foundation provides a good reference for JavaScript.
The JavaScript Console
Data Types
Variables
JavaScript Statements
JavaScript Comments
Operators
Control Structures
Functions
Summary
Exercises
The JavaScript Console
You can start playing around with JavaScript by using the built-in console provided by the different browsers. First open a Web page, e.g. the page [gne.html] that you were working on previously. Then:
Safari
- If you don’t see the Develop menu:
- Menu Safari > Preferences…;
- In the dialog that appears, click on the tab Advanced;
- Check on Show Develop menu in menu bar.
- Menu Develop > Show Error Console….
Firefox
- Menu Tools > Web Developer > Web Console ;
Chrome
- Menu View > Developer > JavaScript Console;
Internet Explorer
- Menu Tools > Developer Tools;
- In the new window at the bottom of the page, click on the tab Console.
Note that in all of these browsers, the Web Inspector used previously and the JavaScript Console share the same window, so you can click on their names in the tabs at the top to switch between them.
Important: Use the console to try out the following bits of JavaScript code! In the examples below the character ⇒ is used to indicate the console's response.
Data Types
JavaScript has many data formats that allow you to store your data sets, from which you can build and manipulate Web pages. The most common ones are:
Numbers
3
3.14159
3.14159e2
The last value is scientific notation and is equal to 3.14159 x 102 = 314.159.
All numbers are stored as double-precision floating point values, meaning they are accurate up to about 15 digits.
Be aware that numbers cannot have commas in them, contrary to common usage! 1,234
would be interpreted as a sequence of two numbers, 1
and 234
.
Character Strings
Like HTML and CSS, JavaScript requires either single or double quotes around text values:
"A piece of text"
'Another piece of text'
Note that if a string begins with one kind of quote, it must also end with the same kind; this allows the use of the other kind in the middle:
"One mo' piece of text"
It’s a good idea to use single quotes when possible to help distinguish JavaScript from the HTML with which it’s often mixed, as the latter commonly uses double quotes for attribute values.
Note that curly quotes, ‘’ and “”, are not relevant here and are treated like any other character.
Arrays
[ 1, 2, 3, 4, 5 ]
[ 'Amherst College', 'Mount Holyoke College',
'Massachusetts Agricultural College', 'Smith College']
Arrays can hold any data type, including other arrays, which is how you could build a multidimensional array, e.g.
[ [1,2] , [3,4] ]
Objects
{ County: 'Hampshire', Organization: 1662, Area: 585,
"Population 1910": 19431, "County Seat": 'Northampton' }
Objects are lists of property: value pairs, and the values can also be any data type.
Objects look similar to CSS styles, but use commas instead of semicolons, and cannot have a trailing comma.
Property names can include spaces if they are enclosed in quotes. To make them more compatible with other programming languages (e.g. SQL), double-quotes are recommended.
Arrays and objects are commonly used together to represent tables in a format known as JavaScript Object Notation (JSON):
[
'....',
{ County: 'Franklin', Organization: 1811, Area: 697,
"Population 1910": 43600, "County Seat": 'Greenfield' },
{ County: 'Hampden', Organization: 1812, Area: 636,
"Population 1910": 231369, "County Seat": 'Springfield' },
{ County: 'Hampshire', Organization: 1662, Area: 585,
"Population 1910": 63327, "County Seat": 'Northampton' },
'....'
]
This example is written for clarity, but for maximum compatibility all properties and string values should be in double quotes, e.g. "County": "Franklin"
. The official JSON format is also more general than this and includes all of the above data types individually or in combination.
You can type any of these data types into the JavaScript console and it will simply print them back for you, except for objects, which for obscure reasons require that you wrap them inside the expression console.log()
, which “logs” the value to the JavaScript console:
console.log({ County: 'Hampshire', Organization: 1662, Area: 585, "Population 1910": 63327, "County Seat": 'Northampton' })
⇒ Object { County: "Hampshire", Organization: 1662, Area: 585, Population 1910: 63327, County Seat: "Northampton" }
Variables
Any of the above data types can be given names that reference their data and allow you to manipulate them, by declaring them as variables with the keyword var
:
var s = 1, schools = 4;
JavaScript is dynamically typed, so that an existing variable can be reassigned to any other kind of data:
schools = [ 'Amherst College', 'Mount Holyoke College',
'Massachusetts Agricultural College', 'Smith College' ];
JavaScript Statements
The variable assignments above are examples of JavaScript statements, code that completes one particular task.
Statements can be terminated with a semicolon, as above, but they aren’t usually required, since JavaScript checks syntax to determine where a statement ends. However, it’s a good idea to include them due to the occasional ambiguities that can occur, as well as minimizing occasional programmer confusion. (Using semicolons also allows code-sharing with C, C++, and Java, which do require them.)
Semicolons also allow more than one statement on a line, e.g. var s = 1; t = s + 2
.
JavaScript statements are usually placed in an HTML <script>
element, which can be anywhere in a document, and is interpreted by the browser as it loads the Web page.
Code that does not directly affect the content of a Web page can be placed in the <head>
element of the document, e.g. initial variable assignments:
<head>
<script type="text/JavaScript">
var someplace = { County: 'Hampshire', Organization: 1662, Area: 585,
"Population 1910": 19431, "County Seat": 'Northampton' };
</script>
</head>
Code that modifies Web page content should be placed in the <body>
at the appropriate point:
<body>
<script type="text/JavaScript">
document.write('<h1>The Geography of New England</h1>');
</script>
....
</body>
You can also place JavaScript code in external files with a statement like
<script type="text/JavaScript" src="gne.js"></script>
In such a file no <script>
element is necessary.
With HTML 5 the attribute type="text/JavaScript"
is optional; while some other languages such as Visual Basic can be used in some contexts, the default scripting language is now JavaScript.
JavaScript Comments
You will want to put explanatory comments in your JavaScript code even more so than with HTML and CSS! Otherwise you will return weeks or months later and not know what you did. See XKCD for an example.
JavaScript provides two ways to write comments, one like in CSS that can appear anywhere and cross lines, and is commonly used for longer comments:
/* This is a comment. */
The second comment format is unclosed, continuing to the end of the line, and is commonly used for shorter comments:
// This is also a comment
Operators
Operators combine different types of data to produce new results.
Unary Operators for Numbers and Strings
Unary operators change a single value to produce a new value.
Numbers can be negated with the familiar unary operator -
:
-2
⇒ -2
The unary operator +
has no effect on numeric values:
+2
⇒ 2
but it will produce automatic type conversion when applied to the text representation of numbers, converting them to actual numbers:
+'3.14'
⇒ 3.14
This is also true of the negation operator.
The functions parseInt()
and parseFloat()
can also be used to convert text to either integer or floating point (decimal) values, respectively, and will correctly handle strings with trailing characters:
parseInt('2px')
⇒ 2
The unary operators increment (++
) and decrement (--
) can be applied to numeric variables to change their values by 1:
var s = 1;
++s
⇒ 2
When these operators are applied following a variable, their values are referenced before they are changed:
s--
⇒ 2
s
⇒ 1
Binary Operators for Numbers and Strings
Binary operators combine two values together to produce a new value.
Numbers can be combined using the familiar binary operators addition (+
), subtraction (-
), multiplication (*
), and division (/
), for example:
2 + 3
⇒ 5
7.1 * 2
⇒ 14.2
The binary +
operator can also be used to concatenate strings (this is known as overloading the operator):
'Lyman' + ' ' + 'R.' + ' ' + 'Allen'
⇒ 'Lyman R. Allen'
Automatic type conversion can occur in some operations, e.g. numbers in text format will be converted to actual numbers when appropriate:
'3.14' * 2
⇒ 6.28
Note, however, that using binary +
with strings and numbers will result in string concatenation:
'3.14' + 2
⇒ '3.142'
Keep this in mind when working with data from the Web, as it will always be character strings to begin with!
To ensure that string “numbers” are converted to actual numbers, precede them by the unary +
operator, which is not overloaded:
+'3.14' + 2
⇒ 5.14
Question: How might you quickly convert a numeric value into a character string?
For each of the above binary operators there are assignment operators +=
, -=
, *=
, /=
that take a variable, apply the operation, and assign the result back to the variable:
s = 7
s /= 2
⇒ 3.5
author = 'Lyman'
author += ' ' + 'Allen'
⇒ 'Lyman Allen'
Using assignment operators is more efficient than the equivalent operations s = s / 2
and author = author + ' ' + 'Allen'
, since the variable is only accessed once.
Array and Object Operators
The individual elements of an array can be selected using the index operator []
, which uses an index from 0
to the array’s length – 1:
var schools = [ 'Amherst College', 'Mount Holyoke College',
'Massachusetts Agricultural College', 'Smith College' ]; // length = 4
schools[0]
⇒ 'Amherst College'
schools[3]
⇒ 'Smith College'
You can also assign values to the individual elements:
schools[2] = 'University of Massachusetts';
And you can append additional values to the array:
schools[4] = 'Hampshire College';
The individual elements in an object can be selected using the property operator .
and the appropriate property:
var someplace = { County: 'Hampshire', Organization: 1662, Area: 585,
"Population 1910": 19431, "County Seat": 'Northampton' };
someplace.County
⇒ 'Hampshire'
There’s also an alternative notation that can be used if the property name has spaces in it (but can be used for any property name written as a string):
someplace["County Seat"]
⇒ 'Northampton'
Multiple levels of data, such as in the JSON table seen earlier, can be referenced by combinations of index operators and properties, e.g.
var mass = [
{ County: 'Barnstable', Organization: 1685, Area: 409,
"Population 1910": 27542, "County Seat": 'Barnstable' },
{ County: 'Berkshire', Organization: 1761, Area: 966,
"Population 1910": 105259, "County Seat": 'Pittsfield' },
{ County: 'Bristol', Organization: 1685, Area: 567, "Population 1910": 318573,
"County Seat": [ 'Fall River', 'New Bedford', 'Taunton' ] },
'....'
];
mass[0].Organization
⇒ 1685
mass[2]["County Seat"][1]
⇒ 'New Bedford'
As with arrays, you can assign values to the individual elements to replace previous values, e.g. to go metric:
someplace.Area *= 1.6093 * 1.6093; // 1.6093 km/mi
⇒ 1515
And you can append additional values:
someplace["Population 2010"] = 158080;
Arrays are actually a particular kind of object, and always have an updated property length
:
schools.length
⇒ 5
To get the length of an object, request its set of properties with the function Object.keys()
, which returns an array whose length you can examine:
Object.keys(someplace)
⇒ Array [ "County", "Organization", "Area", "Population 1910", "County Seat", "Population 2010" ]
Object.keys(someplace).length
⇒ 6
Logical Expressions
Comparison operators test for equality (==
), inequality (!=
), greater than (>
), greater than or equal to (>=
), less than (<
), and less than or equal to (<=
), returning another JavaScript data type, a boolean value:
s = 2 // This is assignment
s == 2 // This is equality; don’t confuse these two!
⇒ true
s > 3
⇒ false
s != 3
⇒ true
The logical operators and (&&
), or (||
), and not (!
) can combine boolean values to produce other boolean values:
true && false // both must be true for the result to be true
⇒ false
true || false // one or the other must be true for the result to be true
⇒ true
! false // must be false for the result to be true
⇒ true
An important application is testing for out-of-bounds conditions on arrays, e.g.
s = -1
s < 0 || s > schools.length // calculated to be true || false
⇒ true
schools[s]
⇒ undefined
In this case trying to use schools[s]
would produce an error, so testing it first allows you to avoid a problem.
Control Structures
A common task in programming is to test the values of variables and then evaluate a block of statements if the comparison is true
or false
.
The if-else
Statement
The basic testing structure is the if-else
statement, which can chain together a series of tests:
var schools = [ 'Amherst College', 'Mount Holyoke College',
'University of Massachusetts', 'Smith College', 'Hampshire College' ];
s = 2
if (s < 0) // Test for out-of-bounds condition
{
console.log('Index == ' + s + ' but must be non-negative.');
}
else if (s >= schools.length) // Test for out-of-bounds condition
{
console.log('Index == ' + s + ' but must be less than ' + schools.length + '.');
}
else
{
console.log('School #' + (s + 1) + ' is ' + schools[s]);
}
⇒ 'School #3 is University of Massachusetts'
The first two statements, if { }
and else if { }
, are used here to test for error conditions, and only if the test is false
will the following statement be executed.
The else { }
statement will only be executed if the earlier ones are false, and in this example is where the desired result is produced.
The statements else if { }
and else { }
are optional, and their use will depend on the type of testing you are doing.
The braces { }
are also optional if they surround only one statement, so for this example they could all be left out, and the structure could be written very compactly as
if (s < 0) console.log('Index == ' + s + ' but must be non-negative.');
else if (s >= schools.length)
console.log('Index == ' + s + ' but must be less than ' + schools.length + '.');
else console.log('School #' + (s + 1) + ' is ' + schools[s]);
The for
Loop
You can also loop through a set of values and do something interesting with them as a variable changes using the for statement:
for (s = 0; s < schools.length; s++)
console.log('School #' + (s + 1) + ' is ' + schools[s]);
⇒
'School #1 is Amherst College'
'School #2 is Mount Holyoke College'
'School #3 is University of Massachusetts'
'School #4 is Smith College'
'School #5 is Hampshire College'
The three statements setting up this for
loop are initialization (s = 0
), test (s < schools.length
), and update (s++
). The first occurs immediately, the second is evaluated at the beginning of each iteration of the loop, allowing it to proceed only if true, and the third is evaluated after the iteration completes.
The function console.log()
is used inside the loop above to ensure the values are printed to the console from each interation of the loop, otherwise only the last will be printed.
When you combine the for
loop with the if
statement, you can test for conditions that let you skip the remainder of the code block with the continue
statement, or exit the loop altogether with the break
statement:
for (s = 0; s < schools.length; s++)
{
if (schools[s] == 'Mount Holyoke College') // Don’t print and go on to next
continue;
if (schools[s] == 'Hampshire College') // Quit the loop early
break;
console.log('One of the Five Colleges: ' + schools[s]);
}
⇒
'One of the Five Colleges: Amherst College'
'One of the Five Colleges: University of Massachusetts'
'One of the Five Colleges: Smith College'
We can use loops to handle the repetitive output of parts of a Web page, for example to format the list of schools from chapter 6.2, we can first write them as pieces of data in an array:
var mass_schools = [
'Amherst College, Non-sect., Amherst.',
'Lasell Seminary, Non-sect., Auburndale.',
'Boston College, R, C., Boston.',
'Boston University, M, E., Boston.',
'Simmons College, Non-sect., Boston.',
'Harvard University, Non-sect., Cambridge.',
'Radcliffe College, Non-sect., Cambridge.',
'Tufts College, Univ., Medford.',
'Smith College, Non-sect., Northampton.',
'Mount Holyoke College, Non-sect., South Hadley.',
'American International College, Cong., Springfield.',
'Wellesley College, Non-sect., Wellesley.',
'Williams College, Non-sect., Williamstown.',
'Clark College, Non-sect., Worcester.',
'Clark University, Non-sect., Worcester.',
'College of the Holy Cross, R. C., Worcester.',
'Massachusetts Agricultural College, Amherst.',
'Massachusetts Institute of Technology, Boston.',
'Worcester Polytechnic Institute, Worcester.'
];
If you store this data in the file mass_schools.js
in a subfolder named js
next to your main document in the gne
folder (a common practice), then you can load it with a <script>
statement in the <head>
of your document:
<script src="js/mass_schools.js"></script>
Then a list can be constructed by inserting JavaScript at the appropriate point in the Web page:
<ol>
<script>
for (s = 0; s < mass_schools.length; s++)
document.write('<li>' + mass_schools[s] +'</li>');
</script>
</ol>
⇒
<ol>
<li>Amherst College, Non-sect., Amherst.</li>
....
</ol>
The JavaScript code in the <script>
element will be evaluated when the browser reaches that point in its interpretation of the HTML, and it will be replaced by the output of the function document.write()
, which will then also be interpreted as HTML. Note that ordinary HTML statements like <ol>
must remain outside of the <script>
element.
If you look at the Web console in your browser, you’ll see both the JavaScript statement and the HTML elements it inserts into the Web page:
The for-in
Loop
There is also a version of the for
loop, commonly called for-in
, that works with objects to step through their property-value pairs:
var someplace = { County: 'Hampshire', Organization: 1662, Area: 585,
"Population 1910": 19431, "County Seat": 'Northampton' };
for (property in someplace)
console.log(property + ': ' + someplace[property]);
⇒
"County: Hampshire"
"Organization: 1662"
"Area: 1412"
"Population 1910: 19431"
"County Seat: Northampton"
"Population 2010: 158080"
Be aware that there is no guarantee that the order that items are originally stored in an object is the same order that they’ll come back out!
Because of the multi-level structure of the JSON table seen earlier, we could use a double loop to get information out of it:
var mass = [
{ County: 'Barnstable', Organization: 1685, Area: 409,
"Population 1910": 27542, "County Seat": 'Barnstable' },
{ County: 'Berkshire', Organization: 1761, Area: 966,
"Population 1910": 105259, "County Seat": 'Pittsfield' },
{ County: 'Bristol', Organization: 1685, Area: 567, "Population 1910": 318573,
"County Seat": [ 'Fall River', 'New Bedford', 'Taunton' ] },
'....'
];
for (county = 0; county < mass.length; county++)
{
someplace = mass[county];
document.write('<tr>');
for (property in someplace)
document.write('<td>' + someplace[property] + '</td>');
document.write('</tr>');
}
But to ensure a specific order a predefined array can be used:
var properties = [ "County", "Organization", "Area", "Population 1910", "County Seat" ];
for (p = 0; p < properties.length; p++)
document.write('<td>' + someplace[properties[p]] + '</td>');
Functions
Functions are a way to package groups of expressions so that they look like a single expression with a well-defined purpose. You can hand functions a set of values (a list of arguments) from which they may return a calculated result or produce some other effect.
We’ve already seen a number of built-in JavaScript functions like parseInt()
, which turns a character string into a number:
parseInt('2px')
⇒ 2
But you can also define your own functions!
Constructing Functions
You’ll want to write your own functions whenever you have a block of code that works with a small amount of information for a particular task. For example, a function to test if a school is one of the Five Colleges can be written with a statement like:
function is5C(name)
{
var schools = [ 'Amherst College', 'Mount Holyoke College',
'University of Massachusetts', 'Smith College', 'Hampshire College' ];
for (var s = 0; s < schools.length; s++)
if (name == schools[s]) return true;
return false;
}
Here, name
is an argument that takes its value when the function is placed in your JavaScript code; when the function is evaluated or called, the return value will take its place:
is5C('Smith College')
⇒ true
is5C('Jones College')
⇒ false
Function arguments such as name
are local variables that are hidden from outside the function. They will also take precedence over the same symbols defined outside, which are global variables.
By declaring the variable schools
inside the function with the keyword var
, it also becomes a local variable.
If a function does not reach an explicit return
statement, it will return after it evaluates its last statement, with a value that is undefined
. This is very common for functions whose purpose is to make other types of changes, and we will see many examples later.
Function definitions are commonly placed in the <head>
of a document, either directly or in external script files, since they don’t actually do anything until they are called, and at that point their definition must already be known to the browser.
For readability purposes a lengthy definition of a function would also be best stored in an external file.
As an example of a lengthy defintion, here is a more involved example that takes a JSON table such as the county data above and summarizes the statistical characteristics of its numerical properties. It shows the extensive testing that might be necessary to ensure that functions don’t fail while dealing with unexpected input:
function summarizeJSONtable(json)
/* Summarize a JSON table (an array of objects) for each numerical property,
returning an object with a set of stats for each, e.g.
{ property1: { count: ..., total: ..., max: ...,
min: ..., stdev: ..., mean: ... },
... }
Allows for data expressed as text as well as
properties that are not completely numeric or are missing.
*/
{
if (!Array.isArray(json))
json = [ json ]; // Make it an array of one item
else if (json.length == 0)
return { }; // Nothing to process
/* Build list of numerical properties and accumulate their values */
var summary = { };
for (var row = 0; row < json.length; row++)
{
if (typeof(json[row]) != 'object')
continue;
for (property in json[row])
{
var datum = json[row][property];
if (typeof(datum) != 'number' && isNaN(datum = +datum))
continue;
if (summary.hasOwnProperty(property)) // already created
{
var stats = summary[property]; // Shorten the repeated reference
stats.count++;
stats.total += datum;
stats.max = Math.max(stats.max, datum);
stats.min = Math.min(stats.min, datum);
stats.stdev += datum*datum;
}
else // create it and seed it
summary[property] = {
count: 1,
total: datum,
max: datum,
min: datum,
stdev: datum * datum
};
}
}
for (property in summary)
{
var stats = summary[property];
stats.mean = Math.round(stats.total / stats.count);
stats.stdev = Math.round(Math.sqrt(
stats.stdev / stats.count - stats.mean * stats.mean ));
}
return summary;
}
summarizeJSONtable(mass)
⇒ {
"Organization": {count: 14, total: 23944, max: 1812, min: 1643,
mean: 1710, stdev: 67, total: 23944 },
"Area": {count: 14, total: 8039, max: 1556, min: 51,
mean: 574, stdev: 382, total: 8039},
"Population 1910": {count: 14, total: 3366416, max: 731388, min: 2962,
mean: 240458, stdev: 231958, total: 3366416 }
}
summarizeJSONtable( { } )
⇒ { }
There is an extensive explanation of the purpose of the function in a comment at the beginning of its definition, a good practice for programming modular items that others might use.
Here is how this function works:
- The function tests its input
json
withArray.isArray()
to determine if it’s in the expected array format, and if it’s not it’s made into an array of length one so that it can be processed by the subsequent code:if (!Array.isArray(json)) json = [ json ];
- If the input
json
is an empty array, the function returns immediately with an empty object:else if (json.length == 0) return { };
- The variable
summary
is assigned to an empty object{ }
to begin, and then the function loops through the array of objectsjson[row]
:
For each row, any numeric properties are added tovar summary = { }; for (var row = 0; row < json.length; row++) { .... }
summary
, as determined by several tests:- The first test for properties uses the
typeof()
function to determine the type of the array itemjson[row]
, returning different values for different data types. If it isn’t an'object'
there are no properties to compile, and the loop continues to the next item:if (typeof(json[row]) != 'object') continue;
- If
json[row]
is an object, the function loops through its properties to test their values, each of which is assigned to the variabledatum
:for (property in json[row]) { var datum = json[row][property]; .... }
- If
typeof(datum)
is not a number then an attempt is made to convert it to one withdatum = +datum
; the latter will always be a JavaScript number but might still be categorized as the special numerical value Not-a-Number, in which caseisNaN()
will also betrue
and the loop continues to the next property:if (typeof(datum) != 'number' && isNaN(datum = +datum)) continue;
- The first test for properties uses the
- Once a numerical value has been established for
datum
, the handling depends on if that property has been previously created insummary
, as determined bysummary.hasOwnProperty()
:- If a property doesn’t already exist, it is assigned an array of initial values, which ensures its
count
is always at least 1 (important for the later calculations that divide by thecount
);summary[property] = { count: 1, total: datum, max: datum, min: datum, stdev: datum * datum };
- If a property already exists,
datum
is added to it in ways that are appropriate for each type of parameter:
Thevar stats = summary[property]; stats.count++; stats.total += datum; stats.max = Math.max(stats.max, datum); stats.min = Math.min(stats.min, datum); stats.stdev += datum*datum;
Math
object provides a number of useful numerical functions, including the two here that provide the larger and smaller of two values.
- If a property doesn’t already exist, it is assigned an array of initial values, which ensures its
Once all of the numerical values are accumulated, the final calculation of the
mean
andstdev
values for each property can occur:var stats = summary[property]; stats.mean = stats.total / stats.count; stats.stdev = Math.sqrt( stats.stdev / stats.count - stats.mean * stats.mean );
Anonymous Functions
It’s also possible to define anonymous functions that can be assigned to variables.
For example, the function is5C
defined above could have been written
is5C = function(name) { /* Statements here */ }
Anonymous functions can be assigned to properties of objects, when they are commonly called methods of the object, and they are automatically provided with a reference to the object in the variable this:
var someplace = { County: 'Hampshire', Organization: 1662, Area: 585,
"Population 1910": 19431, "County Seat": 'Northampton' };
someplace.display = function() { return this["County Seat"] + ', ' + this.County + ' County' };
someplace.display()
⇒ "Northampton, Hampshire County"
The method above requires no arguments, but must still have an empty set of parentheses if you want to get something out of it (as opposed to just passing it around as the function reference someplace.display
).
You will also often see function references handed as arguments to other functions, when they are known as callbacks.
Question: We have already been using an object method on a regular basis; can you think of what it is?
Better Looping with Array Methods
Loops such as for
are one of the most inefficient ways to traverse a set of data in an interpreted language such as JavaScript, so a recent addition to the language is an array method called forEach
, which allows you to hand the array a callback that is applied to each element in the array, in turn:
function printSchools(element)
{
document.write('<li>' + element +'</li>');
}
var mass_schools = [
'Amherst College, Non-sect., Amherst.',
'....',
'Worcester Polytechnic Institute, Worcester.'
];
<ol>
<script>
mass_schools.forEach(printSchools)
</script>
</ol>
⇒
<ol>
<li>Amherst College, Non-sect., Amherst.</li>
....
<li>Worcester Polytechnic Institute, Worcester.</li>
</ol>
The effect of this method is that printSchools()
is called repeatedly, each time with the next string assigned to the argument element
.
Another related and useful array method, map
, returns an array with transformed elements:
mass_schools.map(function (element) { return element.split(', '); })
⇒
[
["Amherst College", "Non-sect.", "Amherst."],
....,
["Worcester Polytechnic Institute", "Worcester."]
]
Note another use of an anonymous function here, defined in-place as the callback argument to map()
; it receives each element of the array of school names in turn, and splits it into an array of individual strings at the character string ', '
. Then map()
returns a new array composed of these subarrays.
Summary
- JavaScript is a full-fledged programming language with
- many data types, viz. nulls, booleans, numbers, character strings, arrays, and objects;
- operators that let you combine these data together;
- variables and functions;
- and has many more built-in functions that are described in the Mozilla Foundation's JavaScript reference.
- JavaScript lets you program the repetitious parts of writing a Web page, inserting HTML directly into a document.
- Browsers can visualize the JavaScript applied to a document’s HTML elements using their built-in Web inspectors.
Exercises
In the Exercises in Chapter 6, you created a Web page gne.html
with styles stored in gne.css
. You can download the reference version of these documents from http://nrcwg01.eco.umass.edu/gne6.4x/ . In the exercises below you’ll replace some of that HTML code with JavaScript. Remember to use the console to test out the different pieces of your code!
- Turn the list of normal schools into an array of strings that are saved into a different file, load that file, and create the HTML using JavaScript.
- Do the same for the table of school populations, writing the data in JSON format. Add a seventh column to the table that displays the fraction of the school population that is foreign-born (calculated with JavaScript, of course!). You might find it helpful to use the Math.round() function.
- Write a function that takes a base URL such as
https://cschweik.gitbooks.io/community-service-with-web-based-gist/content/data/massachusetts_towns_1871/
and the number of tiles it has in each direction and generates the<img>
references for the tile map. Call that function to write the HTML in place. - Save this document, you’ll add more to it in the next section!