This week we will work a bit more with HTML so we can see how to to execute functions on web pages. We will also build on the concept of the function, and add the details of objects to our programming toolbox:
thiskeyword and referencing things
DON'T FORGET!: Your second homework assignment is due at the beginning of class on Thursday this week. If you haven't started it yet, you should probably get busy on it, IMHO. This is just a gentle reminder………
When making web pages that merely display information, it is easy to make the page just display
the information. This is known as a static
web page, because the content doesn't
change. When the web server sends it out, the browser displays it, and that's it. There is no
way for the user to interact with the imformation other than to read it.
What we'd prefer is to be able to use the content to provide information back to the server within the context of the displayed information so that we can cause the server to update the information it displays in real time.
One of the best (or most widely known) examples of this is Google Maps. We all know how this works: you visit the page, type in an address, and the page changes to a map of the area around that address with a virtual pin icon the designated spot. However, the interesting part comes when you drag the map around. Moving the map causes it to be updated with the information which was not visible on the original map. Indeed, *ONLY* the new information is requested from the server, so that the entire page is not refreshed, only the part that is needed is sent and displayed!
JavaScript is a key and fundamental part of this inter-operability, as part of AJAX, which stands
for Asynchronous JavaScript And XML". Let's find out more about these operations.
Last week we saw how to make a button which will change things in the page. The example was very preliminary, but you get the idea. The button is a type of input, and it is connected to a JavaScript function which disables one of the buttons. The connection is made through two pieces, which act like end points. The function must get the identifier of the button to which it will be attached, and the button must tell JavaScript which function to call when it is clicked. Both of these parts must be defined for the button to work.
You can also see from
the example
how to embed a function into the page. Inside the <script> tags you can see the function
named disableElement()
which disables the OK
button on the left. Note
that the function is enclosed within the script tags. We'll play with this a bit more in class
so you can see how things work. Here's the relevant part of the code:
<input type='button' id='firstbtn' value='OK'> <button onclick='disableElement()
'>Disable button</button> <script> functiondisableElement()
{ document.getElementById('firstbtn').disabled=true; } </script>
Another thing to note is that script definition can appear anywhere in the code of the web page
without showing up on the actual page in the browser window. You can define multiple functions
in the same script block, and you can also define all your script functions in a file that can be
included
in the web page source using the <link>
tag in the head
section of the web page source. This allows including multiple JavaScript source code files in
the same web page, which we'll see later when talking about jQuery. Also note that, as shown by
the coloring, the function is defined, but is not actually called specifically; the call is done
by the association with the button's onclick()
property.
An object, as has been said before, is a concept which represents things in the real world in a way that allows grouping their properties with the methods that operate on those properties. In programming language parlance, this means grouping the data with the functions that operate on that data. Here is an example from your text book:
var location = { latitude: 31.131013, longitude: 29.976977 };
The example is an object literal". A literal is a notation for representing
a fixed value; in this case, since the latitude and longitude are specifically defined, the
object is referred to as an object literal. To access the values in the object, JavaScript (and
most other Object-Oriented languages) use the
dot
character, which is the same one
that is used to end a sentence. The pieces that comprise the object are its properties.
For example, in our location object, we can access the latitude property by saying
location.latitude
(read as location dot latitude").
Something to note which may not be obvious: when defining the object's properties, DO NOT USE SEMICOLONS at the end of each property definition. The properties are a comma-separated list!
Quick Quiz:: what is the value of location.longitude
?
Quick Quiz: what error message is produced when the properties are separated by semicolons instead of commas?
Quick Quiz: what is the value of location.north
?
Quick Quiz: is it a syntax error to say location.abcd
?
The answers to the last two questions, of course, are that JavaScript will happily add a new
property called north
to the location object, and will initialize it for you to the
value undefined
. This behavior may seem surprising at first, but it makes perfect
sense in the context of a weakly-typed language. Further, the initialization value also makes
perfect sense, since JavaScript adds the property to the location object, but has no idea to what
value we want it initialized. It's the same situation as:
var north; alert( north );
Although the most usual method to access an object's properties is with the dot operator, there
is another way (which is shown in your text book on page 72), that of using the square brackets.
These are the same square brackets that we saw used to access the elements of an array a couple
of weeks ago. There are plenty of examples provided in the book, so I won't belabor the point
here. There are specific cases in which the dot operator CANNOT be used, and that's where the
square bracket notation comes in. It is illegal to say in JavaScript a.1
(Why?)
Usually, properties are accessed with bracket notation using a quoted string. From our example,
for instance, we can say location["latitude"]
and get the same result as if
we say location.latitude".
Remember that object properties can also be other objects, which can also contain properties that are other objects. This allows us extreme flexibility in defining our own data types, since any object can be defined to contain whatever data or data type we need it to be, along with the functions to operate on that data.
Every JavaScript object has a built-in link to another object, which is hidden from view but can
be accessed by the JavaScript engine (and the programmer, of course). This object is called a
prototype". Prototypes allow several welcome additions to the JavaScript
language:
At its heart, a prototype is just an object from which we can make other objects inherit a set
of properties. It's similar to the Object"built-in class in the Java language; all
javascript objects have a link to the JavaScript prototype by default; that is, any time you
define a JavaScript object, it automatically links to the JavaScript prototype object. If you
then define a sub-class of that object, its prototype is a link to the prototype of its superclass,
which is already linked to the JavaScript prototype. Apart from your text book, there is a
pretty clear description (done in a question-and-answer format) of this mechanism at
this link. There is also more information on the
WikiPedia JavaScript page
under the
Prototype-base
heading.
To create an object from a prototype, we use the Object.create()
function, one of
the built-in functions of the JavaScript language. Here is an example that shows a couple of
interesting things:
var protoCircle = { x: 0, y: 0, radius: 1, color: "black" }; alert( "protoCircle.x = " + protoCircle.x ); alert( "protoCircle.y = " + protoCircle.y ); alert( "protoCircle.radius = " + protoCircle.radius ); alert( "protoCircle.color = " + protoCircle.color ); var c1 = Object.create( protoCircle ); alert( "c1.x = " + c1.x ); alert( "c1.y = " + c1.y ); alert( "c1.radius = " + c1.radius ); alert( "c1.color = " + c1.color ); c1.x = 4; c1.y = 8; c1.radius = 23; c1.color = "green"; alert( "c1.x = " + c1.x ); alert( "c1.y = " + c1.y ); alert( "c1.radius = " + c1.radius ); alert( "c1.color = " + c1.color ); alert( "protoCircle.x = " + protoCircle.x ); alert( "protoCircle.y = " + protoCircle.y ); alert( "protoCircle.radius = " + protoCircle.radius ); alert( "protoCircle.color = " + protoCircle.color );
Note that we define a prototype circle and initialize its properties. When we output the values,
we see that they are what we expect. We then instantiate", or make another
copy, of the protoCircle, called
c1
and see that the values displayed take on those
of the protoCircle automatically! This is because of the inheritance mechanism as we
discussed previously. Next, we assign some new values to the c1
properties and
alert them again to see the new values. Finally, we alert the properties from protoCircle again
and see that these have not changed! We only changed the values for the instantiated class, NOT
for the prototype. They are two distinct objects!
Since JavaScript objects can have properties that are other objects, and those other objects can be from different prototypes, the conceptual view of the software (and of the code) can get really complicated, but don't dispair. There is a LOT of power in this mechanism and you don't have to use it all right away.
Accessing the properties of an object is done, as previously stated, using the dot"
operator. Further, because the function mechanism allows returning a value when the function is
evaluated, you can use the values returned right away as input to other functions! We've seen a
couple of simple examples of this previously, and here is another one:
alert( "your name has " + prompt("your name?").length + " characters." );
The final concept in this section is the idea of searching the prototype chain".
What this means is, when JavaScript is trying to resolve the properties in your objects, it will
look in the nearest matching object to see if one exists (remember
scope"??). If
there isn't one, it will search the object's prototype. If still not found, the prototype's
prototype will be searched, and so on up the chain until the JavaScript built-in prototype is
reached. If the property is not found there, an error message is generated.
Quick Quiz:: what is the error message? Try it and find out.
Most programming languages provide the idea of a function, and since functions (almost always)
return a value, the languages also provide the concept of the data type of the function,
which is the same as the data type of the value it returns. In fact, in programmer's parlance, a
function is often treated as a value for these reasons. We've seen how the returned
value of a function can be immediately used in some other expression or statement, which works
because the function is
a value.
In JavaScript, not only are functions the active parts of a program, they are also objects unto
themselves. Function values, then, are also objects and can have their own properties, just like
any other JavaScript object. The question then, becomes, what kinds of properties can be
part of a function?"
Your text book has a good example, on page 168. Suppose you desired to track the number of times the function got called — you can add a property inside the function to keep track of the count. As another example, suppose you wanted to automatically update some internal property every time the function was called by calling another function. You could add a property to accomplish that as well.
When the function is created, it is given a length
property, and this property is
initialized to the number of parameters that function requires. The function is also given a
prototype
property, which we've just been discussing above.
Here's something else: you can use functions as properties of objects to group lots of them into
a single object so that all the related functionality is collected. This is the very idea behind
the Math
built-in JavaScript object which we've seen in action. (Remember the die
rolling programs in your text book?) This is also part of the philosophy of Object-Oriented
programming, to group things and encapsulate them so that it's easier to remember and
use or re-use things in your programs.
Now we have what we need to create objects and functions that can be created using the magical
operator new
. Because every object in JavaScript automatically has a prototype, and
because functions are objects, functions automatically have prototypes. This means we can define an
object or function, and make functions that belong to the prototype instead of having to
separately define them, or waste space defining functions that will be replicated for every time we
instantiate that object. Functions that are designed in this way, and are called with the operator
new
are called constructors". Here's an example which you should
try out in a script runner or fiddle:
var Person = function( name ) { this.name = name; this.phone = ""; } Person.prototype.getName = function() { return this.name; } Person.prototype.setPhone = function() { this.phone = prompt( "What's your phone number?" ); } var p1 = new Person( "Jim" ); var p2 = new Person( "Bob" ); p1.setPhone(); alert( p2.getName() + " says 'Hi!'" );
Notice a couple of things about this code. First, there are two functions, one to return the name, and one to prompt for the phone number, both of which are part of the prototype of the Person object. This means there is only one copy of each function, which belong to the prototype of the Person object. When we make two instances of the Person object, both of them get access to the functions, instead of having their own copies. This is because of the prototype searching mechanism we saw before.
The second thing to notice is a bit more subtle: we have moved from declaring the variable
named Person
to the function named Person
without any real change
in what we are doing. This is possible because functions are objects.
The final thing to notice is the use of the this
operator. It is used to reference the
object in which it is used. More on this later.
Remember that when we define an object and assign it to a variable, we are really only assigning a reference to that object. Recall the diagram from week four, which is shown again here:
When an object needs to refer to itself, we use the this
operator. Your text book
provides four rules for the use of this keyword. The reason there are four rules (which is a bit
confusing but provides flexibility), is its use depends on the context in which it is applied.
First, this
refers to the global scope when it is used at that level, essentially
the same as just defining the variable at that level.
Second, when this
is used inside a function, it refers to the object through which that
function was called. For example, if an object foo()
has a function bar()
which contains the this
reference, calling the bar()
function will be
referencing the foo
object. By extension then, as shown in your text book, defining
a function outside the object (in the global scope) and then including a reference to the
function in an object definition, makes the this
refer to the object, rather than the
global scope. Here's the code from the text book:
var f = function( x ) { this.y = x + 1; }; var a = { y: 10, op: f }; var b = { y: 20, increment: f }; a.op( 100 ); // the value of a.y will now be 101 b.increment( 43 ); // the value of b.y will now be 44
Notice that the function is defined outside
of the object definitions; it is then assigned
to the objects in variables that are part of these object definitions. Then note how the assignment
causes the this
operation to refer to the correct object.
Third, the logical extension of this situation is that when an object is defined with the new
operator, the this
keyword refers to the object just created. Your text book shows an
important warning with this, however: you must be careful to ALWAYS call such constructors with the
new
operator to avoid writing over ("clobbering") existing global variables
which may have the same name. By convention, JavaScript programmers use the uppercase letter as the
first character in the names of objects and constructors to help avoid clobbering situations.
Finally, there are two built-in methods in the JavaScript function which can be used to force the
this
keyword to refer to something specific. These are the methods apply
and call
which are demonstrated in your text book on page 179.
Continue with more JavaScript, higher-order functions, closures, jQuery, and web page examples. Test in two weeks on Thursday!!!