CIS 89C  Client-Side Programming with JavaScript

 

Unit 9 - Objects (week 4)

 

References:

 

McDuffie - Chapter 16 Creating Custom Objects

 

Topics:

 

Opening statement

Why create a custom object - McDuffie page 566

Creating custom Objects with constructor functions - McDuffie page 566

Extending an Object - McDuffie page 570

The prototype property - McDuffie page 571

            - JavaScript, The Definitive Guide, 5th edition by David Flanagan; O'Reilly

page 138 section 8.6.2

            - JavaScript by Example by Ellie Quigley; Prentice Hall

page 145 section 8.3.3

Using the built-in Object constructor function - McDuffie page 572

Creating a custom Object using an Object literal - McDuffie page 572

Using custom Objects: a real-world example - McDuffie page 572

for … in  and  with

Summary -  McDuffie page 583

 

 

***********************************************************

Opening statement

 

You can use custom Objects as data structures, with data, but no related function.  You can have an Object that contains

firstName    lastName   accountNumber   address   et cetera

for a customer.  You may wish to create many customers with the same properties. 

 

Of course, JavaScript is weak typed, so you are not required to use exactly the same data field properties for each customer Object.

You might add a property for eMail to some of the customers, without adding it to all customer Objects.

 

Because JavaScript is weak typed, there are no fixed constraints on what properties you use.  You can add or delete some data field properties from one of the customer Objects.  So customer objects are not necessarily the same.

You provide the flexibility you need.

 

Of course, the more differences you create in your customer objects, the more code you need to write, to handle all the possibilities.  For example you will need code to handle customer objects that have an eMail property, and customer objects that do not have an eMail property.

 

You can also provide method functions for your objects.  These methods facilitate processing the objects.

 

 

***********************************************************

Why create a custom Object

 

McDuffie gives a couple of good examples of custom Objects.

Menu, Submenu, and MenuItem

These look interesting.

 

You can create Objects needed for the application you are creating.

Perhaps you have phonograph cylinder objects, or phonograph record objects,
or audio CDs, or MP3 CDs, or audio DVDs.  You might have different objects of all of these.  You might have some common properties, such as musical pieces with performers for most of these.  Some of them might have a rotational speed property.

 

 

***********************************************************

Creating custom Objects with constructor functions

 

A constructor function is used to set up an object.

 

Some constructor functions are provided by JavaScript.

Examples are:

The Array() function, used to create an Array object.

The Image() function, used to create an Image object.

 

Examples:

 

var myList = new Array("car", "cat", 54);    // list of three items

var myPicture = new Image(300, 200);       // 300 pixels wide, 200 pixels high

 

To build your own Object with your own constructor function, you must write a constructor function. 

 

Naming constructor functions

You may use any name for your constructor function.

Customarily, you use a name beginning with a capital letter, followed by lower case letters.

 

Use a constructor to set up properties for your object

Typically, your constructor function just puts the parameters into properties of the object.

 

Example from MdDuffie:

 

function Student (firstName, lastName, id)

  {

  this.first = firstName;

  this.last  = lastName;

  this.id    = id;

  this.grade = "";

  }

 

This constructor function just saves the three parameter values in properties.

There is no parameter value for the grade property; it is just set to an empty string.

 

Notice that the current object is referenced by using the keyword this.

this always refers to the current object. 

In this case the current object is the new object, which is being constructed.

 

Then you can use the Student constructor function to set up a couple of your Student Objects:

 

Example:

 

var fred = new Student("Fred", "Schmidt", 123456);

var mary = new Student("Mary", "Jones", 654321);

 

That is all there is to it.

There are no classes or types, such as are used in C++ or other strong typed languages.

 

You have created two objects.  Each time you used the Student constructor.

So, initially, each of the two objects, fred and mary, have the properties:

first     last id   grade

With values given by the arguments you passed to the constructor function,
except grade, which the constructor set to an empty string "".

 

You might be interested in knowing how an object is actually implemented in JavaScript.  It is very simple.  An Object in JavaScript is really just an associative array.  The property names are the keys, and the property values are the corresponding values.  So a property-value pair is implemented as a key-value pair.

 

This is very simple.  There are no class restrictions, so you can add or delete properties at any time.

 

Using object properties

You can access the properties you have created by using the dot notation.

 

Example continued:

 

document.write("First name: ", fred.first);

 

first is the property name you created.

The value you set for the fred object is Fred, so it writes:

 

First name: Fred

 

Creating methods for your custom object

Besides properties, you can also give your custom object methods.

A property is a field of the object, which has a value.

A method is a function of the object.

 

To create a method function, there are two steps:

- write the function

- make the function a property of the object

 

Example (from McDuffie):

 

// *****   function SetGrade is a method for a Student object   *****

function SetGrade( newGrade )

  {

  this.grade = newGrade;

  }

 

this is used to refer to the current object.

Normally methods are used to refer to properties of the current object, although they can also refer to other object's properties or other variables.

 

function Student (firstName, lastName, id)

  {

  this.first = firstName;

  this.last  = lastName;

  this.id    = id;

  this.grade = "";

  this.setGrade = SetGrade;

  }

 

Now the property setGrade is a reference to the global function setGrade.

Of course, the setGrade function does not really work as a global function, because it uses this to refer to the current object.  So, it must be called as a member function.

 

Note: There are two names.  One name for the function, and one name for the method reference property of the object.  I like to use an upper case letter to start the name of the function, and the same name, but starting with a lower case letter for the property that refers to the method function.

 

McDuffie has a confusing way of sometimes capitalizing the first letter in a method name, and sometimes not capitalizing it.  She capitalizes the name of the function, but uses lower case for the property that refers to the function.

 

An alternate, equally confusing way, is to always use a lower case letter to start the name of a method or any other function.  Then you can not tell the difference between the method reference property name and the function name that it refers to.

 

You may do either.  I can't decide which is more confusing.

Of course, you could be completely confusing by using completely different names for the function and for the property that refers to it.

Just remember that the function must have a property set up as a reference to the function, in order to work as a method.

 

Accessing custom object methods

methods are accessed using the dot notation.

The dot notation gives the name of the object first, and establishes it as the current object, which is referenced using this.  The method is after the dot; then, the method can use this to obtain the values of the properties of this object.

 

Example continued:

 

fred.setGrade("A");

document.write("Grade: ", fred.grade);

 

This sets the grade property in the fred object to "A", and then writes it to the document.

 

The setGrade method is a very simple example.  It is better to just set the value of the property directly:

 

Example continued:

 

mary.grade = "A";

document.write("Grade: ", mary.grade);

 

In JavaScript, it is always better to do things the simplest way.

Other languages have fancy techniques to protect the property data, but JavaScript does not.  This makes JavaScript easier to use.  If the program is very large, the techniques used by languages that have strict types and hide the data are better.  For smaller programs, JavaScript is simpler.

 

 

***********************************************************

Extending an Object

 

Extending an object after it has been created is very easy.

If you have any object, and you want to add another property or method to it,

just do it.  There are no type definitions in JavaScript.  So you can just add what you want.

 

Example continued:

 

mary.last = "Johnson";

mary.middle = "Ann";

fred.last = null;

 

function ReversedNameString()

  {

  return ( this.last + ", " + this.first + " " + this.middle ) ;

  }

 

The ReversedNameString() function is obviously intended to be a method, because it uses this to specify the current object.

Now, all we need to do is make it a method of an object.

 

Example continued:  Write this line, then erase it.

 

mary.r = ReversedNameString;

 

I could use r as the name of the reference to the ReversedNameString function.

Perhaps it would be better to change, and do it like McDuffie does it:

 

Example continued: 

 

mary.reversedNameString = ReversedNameString;

 

Now you can use this method of the mary object:

 

Example continued: 

 

document.write( mary.reversedNameString() ) ;

 

This will write:

 

Johnson, Mary Ann

 

 

***********************************************************

The prototype property

 

Discussion is given first in this topic. 

Then discussion is given on why you might want to use this.

Code is given at the end of this section.

 

Discussion

 

Sometimes you want to add a property to a whole class of objects.

JavaScript does not have types, as I have said a hundred times by now.

So the properties are not governed by building a class, as is done in C++.

 

What we do have in JavaScript are prototypes.

Use of prototypes allows us to add a property to several objects, all at once.

 

Every function has a prototype property.

(

  McDuffie says every object has a prototype property. 

  I think she has it backwards.

)

The prototype property of a function refers to a prototype object.

This prototype object is initially empty.

 

So we have:

 

function object    .prototype  -->       prototype object  (initially empty)

 

A function is an object, that has a prototype function, that refers to a prototype object, that is initially empty.

 

IF the function serves as a constructor, then the prototype object can be used to provide properties for the objects built by the constructor function.

 

When the constructor function builds properties in the objects it creates.

The constructor function automatically builds the same properties in the prototype object.

 

All objects built by the same constructor in JavaScript are sometimes called a class.  It is not really a class; a class is a type definition in a strong typed language such as C++ or Java.

 

The neat thing about JavaScript is that, after the objects have been built by a constructor, all the objects in this class can have a new property added to them by simply adding the property to the prototype object.

The properties of the prototype are inherited by all the objects in the class.

 

function object    .prototype  -->       prototype object  (initially empty)

             |

             |

            V

fred object

mary object

joe object

 

The three objects: fred, mary, and joe are created using the same constructor function.

 

Then we add a property to the prototype

 

 

function object    .prototype  -->       prototype object     .middle

             |

             |

            V

fred object

mary object

joe object

 

Now fred, mary, and joe have the middle property.

 

Why would you want to add a property to a class of objects?

 

If you are building 37 objects with the same constructor, and you want them to have a middle property, you can just set up the middle property to the constructor.  Then they would all have the property.  For a middle name property, some people would have a middle name, and those without a middle name could be given an empty string for a middle name.

 

Then all people objects could be processed by a function that prints the first, middle and last names.  Everyone has a middle name property, some of which are an empty string, so nothing prints for their middle name.

 

Why would we want to have a middle property, even for people that have no middle name?  The problem is that if you try to process a property that does not exist, it can sometimes cause processing errors at run time.  You do not want this.  So, give everyone a middle property, even though some are empty.

 

We still have not answered the question, why would you build all these 37 people objects with no middle name, and then use the prototype mechanism to add the middle property later.

 

We want to add properties later, when we did not write the constructor function, but we want an additional property.  When would we use a constructor written by someone else?  This happens all the time.  Often you use a library of code, built for everyone in a project to use.  Often you use a library of code you get from an outside source; either you buy it, or it is free open-source code.  Or, it might be you are using a constructor that is provided as part of the standard code provided with JavaScript for the Document Object Model.

 

The Document Object Model is a very powerful base, on which to work while building web pages from JavaScript code.  It is used in dynamic web pages and Ajax.  So it is widely used in the latest commercial web page development.  Unfortunately, it is much too big a subject for us to use more than a very small part of it in this course.

 

So, you often need to add a property to all the objects in the class of objects built with a constructor, where you got the constructor somewhere, rather than building it yourself.

 

Code

 

// constructor function named Student

// we say all objects built using this constructor

// are in the Student class

function Student (firstName, lastName, id)

  {

  this.first = firstName;

  this.last  = lastName;

  this.id    = id;

  this.grade = "";

  }

 

// create two objects in the student class

var fred = new Student("Fred", "Schmidt", 123456);

var mary = new Student("Mary", "Jones", 654321);

 

// a useful function

function ReversedNameString()

  {

  return ( this.last + ", " + this.first + " " + this.middle ) ;

  }

 

We have a couple problems with the ReversedNameString() function

1) It is a global function, but uses this. 

It would be better if we made it a method of some object, or some objects.

 

Before we fixed this by making it a member of mary:

 

Show and erase:

 

mary. reversedNameString = ReversedNameString;

 

Instead of doing this, lets use the prototype of the constructor, so the ReversedNameString is a method for all the objects in the class.

 

To do this we code:

 

Student.prototype.reversedNameString = ReversedNameString;

 

Now both fred and mary have the reversedNameString property, which refers to the ReversedNameString method.

All additional objects, which we may make later will also have the reversedNameString property.

 

2) Our second problem is that the ReversedNameString function will fail, because there is no middle property.

 

To fix this, we must give every object in the class a middle property:

 

Student.prototype.middle = "";

 

Now all objects in the Student class have an empty string for their middle property.  Because they all have the middle property, the ReversedNameString function will not blow up.

 

3) The only thing left to do is to actually give a middle name to people that have a middle name:

 

mary.middle = "Ann";

 

Now we can use these new properties of fred and mary:

 

document.write( fred. reversedNameString () );

document.write("<br />");

document.write( mary. reversedNameString () );

 

Resulting page:

 

Schmidt, Fred

Jones, Mary Ann

 

This is not a real class, like in Java or C++, but it works, if we are careful to provide all the needed properties.  (Real classes in strongly typed languages require ALL objects in the class have exactly the same properties and methods.)

 

 

***********************************************************

Using the built-in Object constructor function

 

An easy way to build an objects with no initial properties or methods, is to use the built in constructor for an Object; it is the Object() function.

 

var one_off_craft = new Object();

one_off_craft.wingspan = 30;

one_off_craft.fin_length = 2;

one_off_craft.size = function() { return this.wingspan * this.length; }

 

This is an interesting way to write a function.

The function is defined as a method, with a property name size, but the function itself does not have a name.

 

Now you can use this object:

 

document.write("size: ", one_off_craft.size() );

 

 

***********************************************************

The Pollock book does not introduce arrays until Module 11

 

We need to know something about arrays now, if we want to create an
Object Literal.  So, we will look at arrays a little, before discussing an
Object Literal. 

 

A variable can only contain one value.

If you wish to contain several values, you need an array.

There are two types of arrays in JavaScript: indexed arrays, and associative arrays.

 

We will look at associative arrays now.

An Object is implemented in JavaScript as an associative array.

So, anything we can do with an associative array, we can do with an object,
and vise versa.

 

An associative array contains key: value pairs.

Example:

 

key     value

 

red  :    #ff0000

lime :    #00ff00

blue :    #0000ff

 

To create an associative array with these key value pairs we would code:

 

{red: #ff0000, lime: #00ff00, blue: #0000ff}

 

In order to be able to use the associative array, we need to keep a reference to it:

 

var color_chart = {red: #ff0000, lime: #00ff00, blue: #0000ff} ;

 

We can retrieve the values with the dot notation:

 

color_chart.red          has the value #ff0000

color_chart.lime         has the value #00ff00

color_chart.blue         has the value #0000ff

 

 

 

***********************************************************

Creating a custom Object using an Object literal

 

We have been creating objects using a constructor.

 

Example:

 

var mary = new Student("Mary", "Jones", 654321);

 

We have also created objects, using the Object() constructor, which is provided by JavaScript.

 

Example;

 

var mary = new Object();

 

When we create an object using the Object() function as a constructor, we must then add the properties:

 

mary.first = "Mary";

mary.last  = "Jones";

mary.id    = 654321;

 

This example gives us the same mary object, as we built by using the Student() function as a constructor.

 

You remember we can use square brackets to create an Array literal.

 

Example:

 

var count =  [ "zero", "first", "second", 3 ] ;

 

You just put the values in square brackets, separated by commas.

The JavaScript language provides the subscripts 0, 1, 2, 3.

This notation is an easy way to build an array.

 

There is a similar notation, which you can use to build an Object literal.

This notation uses curly braces.

 

Each property is followed by a colon and its value.

These property : value pairs are in a list, separated by commas.

 

Example:

 

var mary = { first : "Mary", last : "Jones", id : 654321 }

 

Again, this gives us the same mary object, as we built in the previous two examples.

 

 

***********************************************************

with

This is part of unit 9

When using the McDuffie book, use this section in unit 7.

When using the Pollock book, use this section HERE in unit 9.

 

This is something different.

There is no particular reason why it is in this unit,

except that, for some reason, McDuffie put it here.

 

Remember that there is always a local scope (which is sometimes "global" to the window).

Remember that there is also a current object (which is usually the current window).

 

When you want to have a different current object, you can specify it using: with

 

Example:

 

A document (page) can have several forms.  The corresponding form objects are kept in an array called: document.forms

Suppose we wish to work with the first form in the array; that would be: document.forms[0]

We might wish to do a number of things with that form, without specifying which form we are using each time.

 

We can use with to specify the form once, and then it will be the current object for the entire block of code following the with specification.

 

with ( document.forms[0] )

  {

  document.write("Form name: ", name);

         // more statements using document.forms[0]

  }

 

This is good to make the code easier to type and easier to read.

When  you just coded name you meant document.forms[0].name

 

 

***********************************************************

Object notation and associative Array notation

 

Objects and associative arrays are similar.

An object has properties and their associated values.

Associative arrays have their keys and their associated values.

 

Examples:

 

document.write ( mary.first );            // Object notation

 

document.write ( mary ["first"] );       // associative Array notation

 

An Object is an associative Array.

You can use either notation.

 

Note that the name of the key must be a string.

The name of the property is given without quotes.

 

The Object format is easier to write.

The associative Array notation is very useful if you are processing strings, and then want to use a string you have built to access the value.

 

 

***********************************************************

Using custom Objects: a real-world example

 

There is a very nice example in the McDuffie book, which uses Objects to implement a multi-level index list.  This is much too long to go through in class.  You can look at it in the book.  If you have the CD-ROM for the book, it is on the CD-ROM.

 

 

***********************************************************

for … in

 

The for … in loop is very good for processing all of the properties in an object or all of the keys in an associative array.

 

An example of the for the for statement is:

 

for ( var my_key_variable in my_associative_array_name)

  {

  document.write (my_key_variable);

  document.write (my_associative_array_name[my_key_variable]);

  document.write (<"br />");

  }

 

This will write out each of the keys with their corresponding value.

 

The required keywords are    for  var  in 

The required punctuations are the braces { } and the square brackets [ ]

The loop variable is given one of the keys each time through the loop.

The loop is executed for each one of the keys, and then ends.

The keys are used in an order determined by the way they happen to be stored.

They are NOT stored in the order you create them.

The system picks an arbitrary order.

 

Notice that I have used square brackets, rather than the dot notation, to get the values corresponding to the keys.  Why?

If you code the name of the key directly in JavaScript, use the dot notation.

If you have a string containing the name of the key, use the square bracket notation.

In this case, either one will work.

 

Of course, this works for objects as well as associative arrays.

my_key_variable is give a string containing the name of one of the properties of the object.

 

The same example of the for the for statement, but using object terminology for the object:

 

for ( var my_property_variable in my_object_name)

  {

  document.write (my_ property_variable);

  document.write (my_object_name[my_ property_variable]);

  document.write (<"br />");

  }

 

We can look at this again, when we study arrays.

A sample will be given in the web page samples there.

 

 

***********************************************************

The Navigator object

 

The Pollock book shows the Navigator Object.

This is an example of an object that is provided with JavaScript.

You should look over this object in the book.

The interesting thing is that you can see what the browser is doing,
by looking at this object.

We will see other built-in objects, that allow us to change the contents of a web page.

This ability to exchange information between JavaScript and the browser activities is very powerful.

 

 

***********************************************************

Summary

 

We have seen that you can build your own Objects.

 

Often you build a constructor function, and use the constructor function to build Objects.  All Objects build by the same constructor are called a class.

( It is not the same thing as a class in C++ or Java. )

You can add more properties or methods to all the Objects in a class by adding them to the prototype property of the constructor function Object.

 

You can also create Objects with no initial properties or methods by using the Object() constructor, which is provided as part of JavaScript.

 

You can also create Objects using the literal notation, with curly braces and a list of property-colon-value pairs.

 

An Object is an associative Array.  You can use either Object notation or Array notation.