CMSI 185: Welcome to Week 08

This Week's Class Agenda

More About Functions and Objects

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:

  1. HTML pages and the script tag
  2. More on defining objects in JavaScript, especially prototypes
  3. Functions as objects
  4. Functions in prototypes
  5. The this keyword 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………

HTML and the <script> Tag

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>
      function disableElement() {
         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.

Object-Oriented Stuff

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.

Functions as Objects

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.

Functions in Prototypes

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.

Referencing in JavaScript

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:

Objects in action

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.

Coming Up Next ...

Continue with more JavaScript, higher-order functions, closures, jQuery, and web page examples. Test in two weeks on Thursday!!!