Reading: JavaScript and JQuery pp 70-75, pp 144-146 on object literals, and pp 450-457 on dates and times.
What have we learned about JavaScript so far?
+
, -
, *
,
/
, %
),
function names (e.g., prompt
, parseInt
),
and method names (e.g., toFixed
).
Expression trees are evaluated from left to right, bottom to top.
Some statements we've seen so far are:
alert(exp);
.
.text()
and .css()
methods:
$(selector).text();
var variable_name = exp;
variable_name = exp;
In variable declarations and assignments, =
is
pronounced gets
and not "equals".
In all of the above statements, exp
can be any
expression, from a simple literal (like 17
or "CS110"
)
or variable (like num
) to a complex expression.
In variable declarations and assignments, the expression on the
right-hand side of =
is first evaluated, and then the
resulting value is assigned to the variable on the left-hand side
of =
. The difference between a variable declaration and an
assignment is that a declaration creates a new variable box whereas an
assignment refers to an existing box.
You should use descriptive names for variables. They greatly help the development of correct programs.
Here's a sample sequence of variable declarations:
var daysInYear = 365; // might sometimes be 366 var minutesInDay = 60 * 24; // really a constant var minutesInYear = daysInYear * minutesInDay;
In the first declaration, the right-hand side is
a simple number value, 365, which is assigned to the variable
daysInYear
. In the second declaration, the right-hand
side is a more complex expression that evaluates to 1440, which is
then assigned to minutesInDay
. In the last declaration,
the right-hand side is an expression involving the variables
daysInYear
and minutesInDay
. Since
daysInYear
has the value 365
and minutesInDay
has the value 1440 when this assignment
occurs, the expression
daysInYear * minutesInDay
evaluates to 525600, which is
then assigned to the variable minutesInYear
.
daysInYear = 365;
365
daysInYearminutesInDay = 60 * 24;
365
daysInYear
1440
minutesInDayminutesInYear = daysInYear * minutesInDay;
365
daysInYear
1440
minutesInDay
525600
minutesInYear
We can display the current date and time on a web page. For example,
the following box is a div with id = date_today
:
If you reload this page, you'll notice that the date and time change appropriately.
Before we explain the JavaScript code that can do this,
we need to understand how time is represented in JavaScript.
We begin by creating a Date
object:
var dateObj2 = new Date();
As we've seen before, the keyword var
in var dateObj2
creates a new
variable box named dateObj2
for storing a
value. What we haven't seen before is the keyword
new
, which causes a
JavaScript object to be created. In this case, the object
represents the current date and time. JavaScript comes equipped with lots
of pre-defined object types like Date
. Stay tuned for a
description of objects.
We can extract information from a Date
object by
invoking methods on it. The table below shows some of the
important methods that Date
objects understand. The elements
of the Value column are dynamically computed by evaluating the
JavaScript expressions in the
Expression column, so reloading the page will update
these appropriately.
Expression | Value | Notes |
---|---|---|
dateObj2.getFullYear() | Full year | |
dateObj2.getYear() | Avoid this! Varies from browser to browser | |
dateObj2.getMonth() | 0=Jan, 1=Feb, ..., 11=Dec | |
dateObj2.getDate() | 1 to 31 | |
dateObj2.getDay() | 0=Sun, 1=Mon, ..., 6=Sat | |
dateObj2.getHours() | 0 to 23 | |
dateObj2.getMinutes() | 0 to 59 | |
dateObj2.getSeconds() | 0 to 59 | |
dateObj2.getTime() | Milliseconds since Jan 1, 1970 (the "epoch") |
Dates are examples of objects. In JavaScript, an object is a kind of value that has two important characteristics:
Both properties and methods are selected from an object using dot
notation. In the examples above, the variable now
contains a date object. The expression to the left of the dot
in dateObj2.getDate()
is a variable,
now
, that contains a date object. To the right of the dot is
the name of the thing we want to compute based on the object. In this
case, we invoke the getDate()
method, which returns the
numerical day of the month in a date object. (You can tell we're calling
a method rather than selecting a property by the presence of parentheses
after the name.)
W3 Schools has a complete list of
methods for Date
objects.
Now let's return to our date and time display. A date object contains a collection of information about the date and time, but for human-readability, we will need to format that data in some conventional way, using, for example, slashes and commas to separate the various numbers.
Here is the date, formatted as is done in the United States and a small
handful of other countries. It is formatted into the following box
which is a div with id = date_today2
. This box has text in Spanish.
<div id="date_today2">Ha cargado esta página en <span class="date"></span> a las <span class="time"></span></div>
Here is JavaScript code that does this (you can also view the page created by embedding this code in a complete HTML file for printing the date):
// create a Date object, representing this moment, and store it var dateObj = new Date(); // format info about the day var the_day = dateObj.getDate(); var the_month = dateObj.getMonth() + 1; // Add 1 because Jan is 0, etc. var the_year = dateObj.getFullYear(); var current_date = the_month + "/" + the_day + "/" + the_year; // format info about the time var the_hour = dateObj.getHours(); var the_minute = dateObj.getMinutes(); var the_second = dateObj.getSeconds(); var current_time = the_hour + ":" + the_minute + ":" + the_second; $('#date_today2 .date').text(current_date); $('#date_today2 .time').text(current_time);
Let's examine the code. It is a sequence of JavaScript statements,
which will be executed sequentially by the browser. The first statement
creates a Date
object representing the current date and time,
and stores it in a variable named dateObj
. Subsequent
statements extract components of this Date
object and piece
them together. The final $().text()
jQuery statements insert
the two strings as the text in the two spans within the div with that id,
thereby displaying the date and time on the page. The surrounding text is
fixed.
As shown below, we could get by with only the single
variable dateObj
. Although the other variables are not
strictly necessary, they can help to make the code more readable. Note
that there's nothing special about naming the
variable dateObj
. We could have called it anything else,
such as today
or now
or fred
(but fred
would not be a good name, since it wouldn't suggest the
meaning or value of the data).
// create a Date object, representing this moment, and store it var dateObj = new Date(); $('#date_today2 .date').text( (dateObj.getMonth() + 1) + "/" + dateObj.getDate() + "/" + dateObj.getFullYear()); $('#date_today2 .time').text( dateObj.getHours() + ":" + dateObj.getMinutes() + ":" + dateObj.getSeconds());
Practice the behavior of the code by using the execution box below. Change the code to display the date in the format that most of the world uses, namely, DD/MM/YYYY.
Remember:
<script>
tags. They are implied.
We've used the example of dates to teach you about:
Lots of other objects and methods exist in JavaScript. One we already
met, namely document.write()
: the document is an object (a
browser has more than one), and one method for operating on that object
is to write some more text into it. We won't be using this method, but
you know about it from your reading.
Here's another method, this time on numbers,
the toFixed()
method:
Ask yourself: what kind of value does val
hold? It
depends on where in the code you're looking; it changes from place to
place. That's why we gave the variable such a vague and unhelpful name:
we couldn't use anything more specific. In fact, the value even
changes datatype from place to place (in the last assignment,
it becomes a string). Since we know that the +
operator
treats strings differently from numbers, this sort of confusion can be a
big problem.
The moral here is that it's not good enough for the JavaScript program to work. The underlying JavaScript code should be easy to read and understand as well!
Let's turn to that now. It makes sense to re-assign to a variable when
it holds the same information (the same meaning and same datatype), but
that the old value needs to be updated. For example, suppose you are
counting something, and the count has changed. In an online shopping
application, you might be counting the number of items the user has in
her cart. Suppose that the variable item_count
stores the
current number of items in the cart. When she adds another item to the
cart, you want to increase that variable's value by one. Here's how:
item_count = item_count + 1;
Notice that if that were a mathematical equality statement, it would be
impossible: no number can equal one more than itself. But this is not
equality, this is assignment, so it says to take the current value
of item_count
, add one to it, and store that value back
into the variable.
Here's a specific example, where we count mouse clicks:
Here's an execution box that will add one more click to your click count and report the current values.
There are three things worth noticing from the code above:
var
out front. The var
tells JavaScript
that we are creating a new variable, and, of course, when we are
re-assigning, we aren't creating a new variable.
=
should be read as "gets". So in the
first line, we are not saying that click_count is equal to
click_count plus one. That would be impossible! Instead, we are saying
that the value assigned to click_count should be updated to the current
value of click_count plus one.
Increasing a variable by some amount is such a common operation in programming that most languages have a shortcut syntax, and JavaScript is no exception. For example, the following two statements mean the same thing:
item_count = item_count + 1; item_count += 1;
In fact, increasing a variable by one is so common that there's an even shorter cut. All three of the following mean the same thing:
item_count = item_count + 1; item_count += 1; item_count++;
All these do is save you some typing. You don't need to use them if you don't want to.
Re-assignment also occurs when we are moving values around. For
example, suppose we are keeping a high score
list of the fastest
clicking users. If someone moves up on the list (gets a new personal
best), we may need to sort the list. One important step in
sorting is swapping values.
Digging into real sorting algorithms is outside the scope of this course, but we do want to look at the issue of swapping values, because it brings up some important issues about how computation works.
Suppose that we declare two variables as follows:
var elmo = 21; var grover = 18;
How can we swap the values in the two variables? That is, how can we
change elmo
to have grover
's value of 18 and
change grover
to have elmo
's value of 21?
The following solution attempt does not work. Why?
elmo = grover; grover = elmo;Use the execution box below (1) to verify that the above solution does not work and (2) to develop a solution that does work.
Note: Your code should work no matter what values are in the two variables. We are using 18 and 21 for concreteness only, but your code should work if they are 7 and 27 or 3 and 92 or ...
The important points are these:
simultaneously
Debugging JavaScript is generally much harder than debugging HTML. As
we've seen, JavaScript has at least two built-in datatypes (numbers, strings), plus
additional kinds of things such as the Date
object, which have their own
rules and constraints. In HTML on the other hand, a tag is either
recognized or it's ignored. There's visual feedback when a tag is
recognized, so you can usually figure out what to do, sometimes with a
little trial and error. That's not to say that HTML is easy, only that it
is easier.
Another thing that makes JavaScript harder to debug is that the browsers are written with regular web surfers in mind, not web page authors. Therefore, the browsers do their best to ignore and suppress JavaScript errors: they are actively trying to hide the errors from you! We already discussed this in a previous lecture; here is a link to the reference material on debugging JavaScript
To test your debugging, visit this page that has some JavaScript Errors.
Note that the errors we are discussing in this section are
syntax errors. The syntax of a programming language is the
set of rules about punctuation (where the commas and semi-colons go),
the order of elements (variables on the left side of an assignment,
expressions on the right), and so forth. These debuggers can help you
find and fix those, but they cannot help you with logic
errors, such as writing “age < 18
”
when you meant to write “age > 18
”.
These are hard to debug, too, because the code
“works” in the sense of producing no errors, but it does
the wrong thing. Your best strategy is to use alert()
to
check whether you are getting to the place in the code that you expect
and whether variables have the values you expect.
Good luck!
The earlier date manipulation code was all numerical. That's partly
because JavaScript is global, and they decided not to have a built-in
function to map month zero to January
when it could just as
easily have been Janvier (French), Enero (Spanish) or Styczen (Polish).
Despite this, we decided to implement a simple function that maps month-numbers (ranging from 0 to 11) to English month-names. Try it out:
Often with objects we will have more than one of them. The methods operate on them in similar ways, yielding similar values, but unique to that object. Here's an example that uses two date objects, so that we can measure the time-difference between them:
The Date()
function makes things called objects.
For, example, the following code creates two date objects, stored in
different variables (start_time
and end_time
),
so that we can determine how long it takes to compute the TOC:
var start_time = new Date(); computeTOC(); // build the table of contents var end_time = new Date(); var elapsed = end_time.getTime() - start_time.getTime(); console.log("building the TOC took "+elapsed+" milliseconds");
It's now time to return to talking about JavaScript objects in general rather than just date objects.
In JavaScript, an object is a collection of data (properties and methods, as we say in our early definition of objects). This collection can be arbitrarily complex, including having other objects inside the containing object (much like a folder can contain other folders), but for now let's keep it simple:
A object is a collection of properties (also called keys) and values. We use the properties (keys) to look up the values. We'll use the termspropertiesandkeysinterchangeably
We'll ignore methods for now and focus on properties.
Let's be concrete. Imagine that we have an object to keep track of a
user's info, including their name, year of graduation and whether
they're going to the party. So, the three properties will be:
(1) name
, (2)
gradYear
, and (3) going
.
We'll begin with a particular person, Alice, who is the class of 2013
and is going to the party. We'll store all that info in a single object
and we'll store the object in a variable called person1
.
We can make a second object about another person, Betty.
Consider the following JavaScript code:
var person1 = {name: "Alice", gradYear: 2013, going: "yes"}; var person2 = {name: "Betty", gradYear: 2014, going: "no"};
Try copy/pasting that code into a JavaScript console. Look at the resulting objects:
>>> person1 >>> person2
Firebug even has a cool dir
feature that breaks out all
the properties into separate, clickable things. This is particularly
useful for big, complicated objects, such as windows. Try it:
>>> dir(person1) >>> dir(window)
Let's repeat those assignment statements, together with an abstraction:
var person1 = {name: "Alice", gradYear: 2013, going: "yes"}; var person2 = {name: "Betty", gradYear: 2014, going: "no"}; var person2 = {prop1: value1, prop2: value2, prop3: value3};
The things on the right hand side are called object literals. The syntax of an object literal is an opening brace, a series of property/value pairs separated by commas, and a closing brace. Each property/value pair consists of a property (which follows the same rules as the names of variables), a colon, and a value. The value can be any JavaScript value, such as a number, string, or another object. Each of these object literals has three property/value pairs, but a JavaScript object can have any number of pairs, including none:
var empty_person = {};
One use for the object literal syntax is to collect several related
items so that you can refer to them as a collection instead of separate
pieces of information. For example, the jQuery .css()
method allows you to change a CSS property of the selected elements, but
if you pass in an object literal of several changes, you can change them
all at once. For, example, consider the following box:
This sets the width and height in two steps:
This sets the width and height in one step:
You can even animate the transitions:
This animates the box getting bigger.
And this animates the box getting smaller.
Notice how in the animations we packaged up our target measures into an
object, stored that object in a variable with a nice, helpful name, and
then referred to the variable in the animate()
method.
Date
object is used to manipulate dates and time.
The expression new Date()
creates a
Date
object representing the current date and time.
Methods like getMonth()
and getHours()
are used to extract components from a Date
object.
Beyond here is information that we think you might find interesting and useful, but which you will not be responsible for yet. It's for the intellectually curious student. We will be getting to many of these concepts a bit later in the course, so it would useful to pass your eyes over this once, just to start the learning process. Don't worry if some of it doesn't make sense yet.
One of our go-to debugging tools is to use the alert
function to report a value. Unfortunately, alert
doesn't
work so well with objects. Try it:
Fortunately, there's an easy solution. All modern browsers have a JSON
object that has a method called stringify
.
The stringify
method takes an JavaScript Object and
converts it into a string. You can then hand that string to
the alert
function:
Given an object, there are a few things you might want to do (operations on it):
Here are some specific examples of those operations with
the person1
object:
You'll notice that the way we add a new property/value pair is identical to the way we modify an existing property/value pair: just an assignment statement. That's because JavaScript creates the property if necessary, and then updates the value. In practice, removing a property/value pair is rarely done, so we really only need to remember two operations: getting and setting.
Here are two assignment statements that demonstrate both getting and setting. On the right hand side, we get a value out of one object and on the left hand side we set a value of an object.
The syntax for getting and setting look the same: a variable, a dot, and a property.
The markers on a Google Map are another example of objects. Those
markers are objects with properties like lat
and lng
(latitude and longitude), along with other info.
For example, something like:
var marker1 = {lng: 42.296612,lat: -71.301956}; // Wellesley
The syntax we learned above to get and set a value in an object
(variable.property
) is simple and effective but fails in two
cases: if the property is unknown and if the property contains odd characters,
such as spaces or hyphens.
For example, suppose instead of calling the property gradYear
,
we wanted to call it grad year
(with a space in it). The
following doesn't work at all:
person1.grad year = 2014;
Usually, we can get around this very simply by limiting ourselves to property names that don't have spaces, hyphens, semi-colons and other oddities.
A slightly more difficult case comes where we don't know the property
in advance. For example, we have an object that stores the dimensions
of an image, with properties width
and height
.
We want to retrieve the larger dimension, and we've stored the property
in a variable called larger_dim
. The following fails,
because it tries to look up a property named larger_dim
instead of one named height
.
There is a solution to both problems: the syntax to get/set a value in an object can be a string in square brackets. Here's an example that works. Note that the expression in the square brackets is a literal string.
Here's the same syntax used to solve the second problem of an unknown
property. Note that here, the expression in the square brackets is
a variable (larger_dim
) that contains a string.
In fact, if you want to, you can always use the square bracket notation, and ignore the dot notation. For example:
However, most programmers appreciate the brevity and reduced punctuation of the dot notation, so you will see it a lot.
Sometimes it's useful to be able to loop over all the properties of an object. JavaScript has a built-in syntax, a special kind of loop, for doing just that. For example, the following will alert all the properties in an object:
The following variation alerts all the values in an object. Note that
using the square bracket notation is necessary here, because each time
through the loop the variable prop
has a different value.
The syntax for this loop is
for ( P in OBJ ) { // loop body here }
We haven't studied loops, and we generally won't, so this topic is
outside the scope of this class (though just barely). Nevertheless, the
basic idea is that the code in the braces (called the body of
the loop) is executed many times, once for each property in the
object. The P
is a new variable (like one created
by the var
keyword) and it is given a value (as if by an
assignment statement) before each time through the body of the
loop. Those values will the properites of the object.
The OBJ
is an existing variable that holds an
existing object.
Here's one last example, which counts the number of properties in an object. Note the shortcut for incrementing the counter.