The purpose of this series of lessons is to teach you how to program
in JavaScript. The goal is to provide a programming tutorial that
will be accessible to persons with no programming experience and will be
equally useful to persons who already have programming experience using
JavaScript or some other language.
One important thing that you haven't learned yet is how to create your
own object types and instantiate new objects from those types. That
is the primary subject of this lesson.
You can also create your own object types and instantiate new objects from those types. There are essentially two ways to do this.
x1 = object1.getData(); x2 = object2.getData(); x3 = object3.getData(); |
this is a special JavaScript keyword that you can use
inside a method to refer to the specific object on which the method was
invoked. We will see examples of the use of this in
the sample scripts in this lesson.
You learned how to use the constructor function in earlier lessons to
instantiate new objects from predefined object types using code such as
the following:
newDateObject = new Date(); |
Defining a new object type and creating a new object using a constructor involves two steps:
The following code fragment shows the constructor for this new object
type named myObjectType.
function myObjectType(intData, stringData){//constructor this.intData = intData; this.stringData = stringData; }//end constructor |
The next code fragment that we want to look at illustrates how this
constructor can be used to instantiate one or more objects of the new type.
This code fragment instantiates two objects of the type and then accesses
and displays the property values of each of the objects. (The function
named d() is a general purpose display function. You can see
the code for this lesson in the complete listing of the script following
this discussion.)
obj1 = new myObjectType(5, "obj1"); obj2 = new myObjectType(10, "obj2"); d("obj1 contains: ",obj1.intData," ",obj1.stringData); d("obj2 contains: ",obj2.intData," ",obj2.stringData); |
<!-- File Js00000420.htm Copyright 1998, R.G.Baldwin This script is designed to illustrate defining and instantiating new object types. The output from running this script is: obj1 contains: 5 obj1 obj2 contains: 10 obj2 Done. --------------------------------------------------------------------> <HTML> <HEAD> <SCRIPT LANGUAGE="JavaScript1.2"> <!-- Hide script function d(){//simple display function for(cnt = 0; cnt < d.length; cnt++) document.write(d[cnt]);//end for loop document.write("<BR>");//write a line break }//end function function myObjectType(intData, stringData){//constructor this.intData = intData; this.stringData = stringData; }//end constructor // End hiding --> </SCRIPT> </HEAD> <BODY> <SCRIPT> <!-- Hide script obj1 = new myObjectType(5, "obj1"); obj2 = new myObjectType(10, "obj2"); d("obj1 contains: ",obj1.intData," ",obj1.stringData); d("obj2 contains: ",obj2.intData," ",obj2.stringData); // End hiding --> </SCRIPT> <P> Done. </BODY> </HTML> |
Also in an earlier lesson, we saw how it is possible to make use of the argument array to create a crude form of function overloading in JavaScript. We can use that capability to create overloaded constructors for a new object type.
I do want to provide a cautionary note at this point. The complexity of this approach could get out of hand very quickly. This is particularly true in those cases where objects instantiated from the different versions of the constructors need to have methods with the same names and different behavior. This would entail implementing function overloading within function overloading and, while possible, might be difficult to accomplish.
The next sample script upgrades the previous script to provide constructors that are overloaded to accommodate different numbers of parameters.
The structure of this overloaded constructor, at this point, is essentially the same as the overloaded function that we illustrated in a previous lesson. We will upgrade it in a subsequent sample script.
The overloaded constructor function determines the length of the argument array whose name is the same as the name of the function, myObjectType. A switch statement is used to select among three different blocks of code based on the length of that array (the number of parameters).
For the case of one parameter, the code stored the incoming parameter into one of the properties and initialized the other property with the string "Not initialized".
For the case of two parameters, the code stored the two incoming parameters in the two properties of the object. Although it isn't necessary to require that all versions of the object have the same number and type of properties, this is probably a practical requirement later when time comes to provide methods that manipulate those properties.
For the case where the number of arguments was neither one nor two, an error message was displayed.
While an error message might be useful for human consumption, it probably isn't too useful for programming. A better solution to this problem might be to cause the first two blocks of code to return true and cause the default code to return false.
Then the code that instantiates the object could test the return value
to determine if the instantiation was or was not successful. (Recall
that I told you in the earlier lesson on function overloading that this
is not a problem with other OOP languages such as C++ and Java. Those
languages would determine at compile time that the arguments being passed
to the constructor don't match a valid constructor.)
function myObjectType(){//constructor len = myObjectType.length; switch(len){ case 1: this.intData = myObjectType[0]; this.stringData = "Not initialized"; break; case 2: this.intData = myObjectType[0]; this.stringData = myObjectType[1]; break; default: d("Not defined for ",len," parameters."); }//end switch }//end constructor |
Then the properties of the two valid objects are displayed.
obj1 = new myObjectType(5); obj2 = new myObjectType(10, "obj2"); obj3 = new myObjectType(10, "obj3", "Third parameter"); |
<!-- File Js00000430.htm Copyright 1998, R.G.Baldwin This script is designed to illustrate a crude form of overloaded constructors. The output from running this script is: Not defined for 3 parameters. obj1 contains: 5 Not initialized obj2 contains: 10 obj2 Done. --------------------------------------------------------------------> <HTML> <HEAD> <SCRIPT LANGUAGE="JavaScript1.2"> <!-- Hide script function d(){//simple display function for(cnt = 0; cnt < d.length; cnt++) document.write(d[cnt]);//end for loop document.write("<BR>");//write a line break }//end function function myObjectType(){//constructor len = myObjectType.length; switch(len){ case 1: this.intData = myObjectType[0]; this.stringData = "Not initialized"; break; case 2: this.intData = myObjectType[0]; this.stringData = myObjectType[1]; break; default: d("Not defined for ",len," parameters."); }//end switch }//end constructor // End hiding --> </SCRIPT> </HEAD> <BODY> <SCRIPT> <!-- Hide script obj1 = new myObjectType(5); obj2 = new myObjectType(10, "obj2"); obj3 = new myObjectType(10, "obj3", "Third parameter"); d("obj1 contains: ",obj1.intData," ",obj1.stringData); d("obj2 contains: ",obj2.intData," ",obj2.stringData); // End hiding --> </SCRIPT> <P> Done. </BODY> </HTML> |
The constructor for this new object type looks just like the constructor
for our previous definitions of new object types. The constructor
simply uses this to save the incoming parameters, including
the date object, in a variable of the new object.
function myObjectType(theString,theDate){//constructor this.theString = theString; this.theDate = theDate; }//end constructor |
Note in particular the highlighted portion of this fragment which reads obj.theDate.getMonth(). Note that this expression contains two periods whereas before we have seen the use of only one period in expressions similar to this one. In this case, the following expression (note that this is only part of the overall expression)
obj.theDate
extracts the Date object from the object named obj. The Date object then replaces the first two terms in the overall expression providing a result that is analogous to the following expression (that never really exists).
(the date object).getMonth()
At this point in the execution of the script, we have the method named
getMonth() being invoked on the date object that was fetched by
the first two terms in the expression. This returns the month portion
of the date contained in the Date object which is passed to the
method named d() for display.
obj = new myObjectType("Dick Baldwin", new Date()); d(obj.theString," Month number ",obj.theDate.getMonth()); |
The output from running this script is shown at the beginning of the
listing that follows.
<!-- File Js00000440.htm Copyright 1998, R.G.Baldwin This script is designed to illustrate the use of objects as properties of another object. The output from running this script is: Dick Baldwin Month number 4 Done. --------------------------------------------------------------------> <HTML> <HEAD> <SCRIPT LANGUAGE="JavaScript1.2"> <!-- Hide script function d(){//simple display function for(cnt = 0; cnt < d.length; cnt++) document.write(d[cnt]);//end for loop document.write("<BR>");//write a line break }//end function function myObjectType(theString,theDate){//constructor this.theString = theString; this.theDate = theDate; }//end constructor // End hiding --> </SCRIPT> </HEAD> <BODY> <SCRIPT> <!-- Hide script obj = new myObjectType("Dick Baldwin", new Date()); d(obj.theString," Month number ",obj.theDate.getMonth()); // End hiding --> </SCRIPT> <P> Done. </BODY> </HTML> |
function newType(theString,theDate){//constructor this.theString = theString; this.theDate = theDate; }//end constructor |
However, this function is significantly different from others like it that you have seen previously. The difference has to do with how the the function gains access to the Date object from which it will extract the information. In this case, it was necessary to plan this function in advance as one that would become a method of an object of type newType. Having determined this, it was obvious where the Date object would come from. It would be a property of an object of type newType.
Since the Date object will be a property of an object, and this function will be a method of the same object, the code in the function can access the Date object using this. However, the code in the function also has to know the name of the property that represents the Date object. So, you will see several expressions in the following code similar to this.theDate.getDate().
Technically, any function could be added to an existing object and considered
to be a method of the object. However, it is important to realize
that not just any function can be added to an object to become a useful
method of that function. Because of names and other considerations,
if the method is to be able to access the properties of the object, or
any other data stored in the object, that must be taken into account when
the function is written.
function showDate(){ d("The string is ",this.theString); theMonth = this.theDate.getMonth() + 1; theDay = this.theDate.getDate(); theYear = this.theDate.getYear(); theHour = this.theDate.getHours(); if(theHour > 12){ theHour -= 12; amPm = " PM"; }else amPm = " AM"; theMin = this.theDate.getMinutes(); d("The date and time is ",theHour,":",theMin,amPm, " on ",theMonth,"/",theDay,"/",theYear); }//end function showDate() |
obj = new newType("Dick Baldwin", new Date());//create object obj.showDate = showDate;//add method to the object obj.showDate();//invoke the method on the object |
obj = new newType("Dick Baldwin", new Date());//create object obj.theMethod = showDate;//add method to the object obj.theMethod();//invoke the method on the object |
<!-- File Js00000450.htm Copyright 1998, R.G.Baldwin This script is designed to illustrate adding a method to an existing object. The output from running this script is: The string is Dick Baldwin The date and time is 9:56 AM on 5/26/98 Done. --------------------------------------------------------------------> <HTML> <HEAD> <SCRIPT LANGUAGE="JavaScript1.2"> <!-- Hide script function d(){//simple display function for(cnt = 0; cnt < d.length; cnt++) document.write(d[cnt]);//end for loop document.write("<BR>");//write a line break }//end function function newType(theString,theDate){//constructor this.theString = theString; this.theDate = theDate; }//end constructor function showDate(){ d("The string is ",this.theString); theMonth = this.theDate.getMonth() + 1; theDay = this.theDate.getDate(); theYear = this.theDate.getYear(); theHour = this.theDate.getHours(); if(theHour > 12){ theHour -= 12; amPm = " PM"; }else amPm = " AM"; theMin = this.theDate.getMinutes(); d("The date and time is ",theHour,":",theMin,amPm, " on ",theMonth,"/",theDay,"/",theYear); }//end function showDate() // End hiding --> </SCRIPT> </HEAD> <BODY> <SCRIPT> <!-- Hide script obj = new newType("Dick Baldwin", new Date());//create object obj.showDate = showDate;//add method to the object obj.showDate();//invoke the method on the object // End hiding --> </SCRIPT> <P> Done. </BODY> </HTML> |
The following sample script is a little more elaborate than the previous one. In addition to providing the method definition in the constructor, it also provides two different constructors for two different object types. These two constructors each define a method, and they share the same actual function for that method.
The following fragment shows the first of two constructors. This is the constructor for an object type named NewType. Other than the method definition, there is nothing new here.
Pay particular attention to the syntax of the method definition for a method named theMethod that is highlighted in boldface. Note that this statement refers to a method and a function but there are no parentheses in this statement.
This statement says that this object has a method named
theMethod() which is actually implemented by making a call to the
function named showDate(). Any parameters that are passed
to theMethod() will be automatically passed to showDate()
(although there aren't any parameters in this sample script). The
system probably treats theMethod simply as an alias for showDate
but I don't know that for sure.
function NewType(theString,theDate){ this.theString = theString; this.theDate = theDate; this.theMethod = showDate; }//end constructor |
The most important thing about this constructor is that it also defines
a method and shares the showDate() function with the previous constructor.
This illustrates that constructors can share functions for use as methods
provided that the behavior of the function is appropriate for objects of
all the types that share it.
function AnotherNewType(theString,anotherString,theDate){ this.theString = theString; this.anotherString = anotherString; this.theDate = theDate; this.theMethod = showDate; }//end constructor |
function showDate(){ theMonth = this.theDate.getMonth() + 1; theDay = this.theDate.getDate(); theYear = this.theDate.getYear(); theHour = this.theDate.getHours(); if(theHour > 12){ theHour -= 12; amPm = " PM"; }else amPm = " AM"; theMin = this.theDate.getMinutes(); d("The date and time is ",theHour,":",theMin,amPm, " on ",theMonth,"/",theDay,"/",theYear); }//end function showDate() |
//Instantiate object of one type obj1 = new NewType("Dick Baldwin", new Date()); d(obj1.theString);//display a property of the object obj1.theMethod();//invoke the method on the object //Instantiate an object of another type obj2 = new AnotherNewType("Tom Jones","Sue Smith",new Date()); d(obj2.theString," ",obj2.anotherString);//display properties obj2.theMethod();//invoke the method on the object |
<!-- File Js00000460.htm Copyright 1998, R.G.Baldwin This script is designed to illustrate inclusion of methods in the defintion of a constructor function. The output from running this script is: Dick Baldwin The date and time is 10:56 AM on 5/26/98 Tom Jones Sue Smith The date and time is 10:56 AM on 5/26/98 Done. --------------------------------------------------------------------> <HTML> <HEAD> <SCRIPT LANGUAGE="JavaScript1.2"> <!-- Hide script function d(){//simple display function for(cnt = 0; cnt < d.length; cnt++) document.write(d[cnt]);//end for loop document.write("<BR>");//write a line break }//end function //One constructor function NewType(theString,theDate){ this.theString = theString; this.theDate = theDate; this.theMethod = showDate; }//end constructor //Another constructor function AnotherNewType(theString,anotherString,theDate){ this.theString = theString; this.anotherString = anotherString; this.theDate = theDate; this.theMethod = showDate; }//end constructor //Shared function function showDate(){ theMonth = this.theDate.getMonth() + 1; theDay = this.theDate.getDate(); theYear = this.theDate.getYear(); theHour = this.theDate.getHours(); if(theHour > 12){ theHour -= 12; amPm = " PM"; }else amPm = " AM"; theMin = this.theDate.getMinutes(); d("The date and time is ",theHour,":",theMin,amPm, " on ",theMonth,"/",theDay,"/",theYear); }//end function showDate() // End hiding --> </SCRIPT> </HEAD> <BODY> <SCRIPT> <!-- Hide script //Instantiate object of one type obj1 = new NewType("Dick Baldwin", new Date()); d(obj1.theString);//display a property of the object obj1.theMethod();//invoke the method on the object //Instantiate an object of another type obj2 = new AnotherNewType("Tom Jones","Sue Smith",new Date()); d(obj2.theString," ",obj2.anotherString);//display properties obj2.theMethod();//invoke the method on the object // End hiding --> </SCRIPT> <P> Done. </BODY> </HTML> |
Caution: While working with the next sample script, I
noticed that the algorithm that I have been using throughout this tutorial
to convert time from the Date object into AM/PM representation isn't
correct for the hour immediately following 12:00 noon. This hour
is reported as being AM when it should be PM. If you adopt this algorithm
for your own use, be sure to modify it to correct this bug.
|
We need to confirm that we can instantiate multiple objects of
the same type, all of which have the same method based on the same function,
and the method will treat the data in each object independently of the
other objects. That confirmation is provided in the following sample script.
This script defines an object constructor that has a method very similar
to the previous script. Therefore, we won't show that part of the
script in these fragments. You can see the constructor in context
in the listing of the script that follows this discussion.
The following fragment shows the instantiation and display of the contents of two objects of the same type: obj1 and obj2.
After the first object was instantiated and displayed, a delay was forced into the script to allow the clock to turn over before instantiating the next object. This was done to cause the contents of the Date object to be different between the two object.
After the second object was instantiated, its contents were displayed.
Then the contents of the first object were displayed again to confirm that
they had not been corrupted by some unplanned interaction with the second
object.
d("Instantiate and display first object"); obj1 = new NewType("First Object", new Date()); d(obj1.theString);//display a property of the object obj1.theMethod();//invoke the method on the object d("Force a delay to let the clock turn over"); for(cnt1 = 200000; cnt1 > 0; cnt1--){ dummy = 0; }//end for loop<BR> d("Instantiate and display second object"); obj2 = new NewType("Second Object", new Date()); d(obj2.theString);//display a property of the object obj2.theMethod();//invoke the method on the object d("Display first object again"); d(obj1.theString);//display a property of the object obj1.theMethod();//invoke the method on the object |
This output shows that instantiating and manipulating a second object
of the same type did not corrupt the data stored in the properties of the
first object.
<!-- File Js00000470.htm Copyright 1998, R.G.Baldwin This script is designed to illustrate inclusion of methods in the definition of a constructor function and the instantiation and use of multiple objects of that type.. The output from running this script is: Instantiate and display first object First Object The date and time is 12:45 AM on 5/26/98 Force a delay to let the clock turn over Instantiate and display second object Second Object The date and time is 12:46 AM on 5/26/98 Display first object again First Object The date and time is 12:45 AM on 5/26/98 Done. --------------------------------------------------------------------> <HTML> <HEAD> <SCRIPT LANGUAGE="JavaScript1.2"> <!-- Hide script function d(){//simple display function for(cnt = 0; cnt < d.length; cnt++) document.write(d[cnt]);//end for loop document.write("<BR>");//write a line break }//end function //constructor function NewType(theString,theDate){ this.theString = theString; this.theDate = theDate; this.theMethod = showDate; }//end constructor function showDate(){ theMonth = this.theDate.getMonth() + 1; theDay = this.theDate.getDate(); theYear = this.theDate.getYear(); theHour = this.theDate.getHours(); if(theHour > 12){ theHour -= 12; amPm = " PM"; }else amPm = " AM"; theMin = this.theDate.getMinutes(); d("The date and time is ",theHour,":",theMin,amPm, " on ",theMonth,"/",theDay,"/",theYear); }//end function showDate() // End hiding --> </SCRIPT> </HEAD> <BODY> <SCRIPT> <!-- Hide script d("Instantiate and display first object"); obj1 = new NewType("First Object", new Date()); d(obj1.theString);//display a property of the object obj1.theMethod();//invoke the method on the object d("Force a delay to let the clock turn over"); for(cnt1 = 200000; cnt1 > 0; cnt1--){ dummy = 0; }//end for loop<BR> d("Instantiate and display second object"); obj2 = new NewType("Second Object", new Date()); d(obj2.theString);//display a property of the object obj2.theMethod();//invoke the method on the object d("Display first object again"); d(obj1.theString);//display a property of the object obj1.theMethod();//invoke the method on the object // End hiding --> </SCRIPT> <P> Done. </BODY> </HTML> |
In this section, we will learn how to add a new property to an existing object type, meaning to change the basic type definition to include the new property. This will effect all objects of the type including all existing objects of the type..
This script begins with an ordinary constructor to define a new object type named NewType that has two properties:
function NewType(theString,theInt){ this.theString = theString; this.theInt = theInt; }//end constructor |
d("Instantiate and display first object"); obj1 = new NewType("First ", true); d(obj1.theString,obj1.theInt); d("Instantiate and display second object"); obj2 = new NewType("Second ", false); d(obj2.theString,obj2.theInt); d("Instantiate and display third object"); obj3 = new NewType("Third ", true); d(obj3.theString,obj3.theInt); |
This is accomplished using the following statement. Note in particular the syntax of this statement and the use of the prototype property.
In addition to adding the new property to all objects of this type,
this statement also initializes that property to null in all existing
objects.
NewType.prototype.newProperty = null; |
Here we want to make a distinction between null and undefined.
To accomplish this, we display all three properties in all three objects
and also attempt to display the contents of another property named junk
that has never been defined. If everything goes according to plan,
the junk property should show to be undefined in all objects.
The newProperty property should have values of 3.14 and 6.28
in the first two objects respectively and null in the third object.
obj1.newProperty = 3.14; obj2.newProperty = 6.28; d(obj1.theString,obj1.theInt," ",obj1.newProperty," ",obj3.junk); d(obj2.theString,obj2.theInt," ",obj2.newProperty," ",obj3.junk); d(obj3.theString,obj3.theInt," ",obj3.newProperty," ",obj3.junk); |
<!-- File Js00000480.htm Copyright 1998, R.G.Baldwin This script is designed to illustrate the addition of a new property to an object type, thereby changing the basic definition of the type. The output from running this script is: Instantiate and display first object First true Instantiate and display second object Second false Instantiate and display third object Third true Add a new property to NewType and initialize to null. Populate two objects, display all three. Try to display undefined property on all objects. First true 3.14 undefined Second false 6.28 undefined Third true null undefined Done. --------------------------------------------------------------------> <HTML> <HEAD> <SCRIPT LANGUAGE="JavaScript1.2"> <!-- Hide script function d(){//simple display function for(cnt = 0; cnt < d.length; cnt++) document.write(d[cnt]);//end for loop document.write("<BR>");//write a line break }//end function //constructor function NewType(theString,theInt){ this.theString = theString; this.theInt = theInt; }//end constructor // End hiding --> </SCRIPT> </HEAD> <BODY> <SCRIPT> <!-- Hide script d("Instantiate and display first object"); obj1 = new NewType("First ", true); d(obj1.theString,obj1.theInt); d("Instantiate and display second object"); obj2 = new NewType("Second ", false); d(obj2.theString,obj2.theInt); d("Instantiate and display third object"); obj3 = new NewType("Third ", true); d(obj3.theString,obj3.theInt); d("Add a new property to NewType and initialize to null."); d("Populate two objects, display all three."); d("Try to display undefined property on all objects."); NewType.prototype.newProperty = null; obj1.newProperty = 3.14; obj2.newProperty = 6.28; d(obj1.theString,obj1.theInt," ",obj1.newProperty," ",obj3.junk); d(obj2.theString,obj2.theInt," ",obj2.newProperty," ",obj3.junk); d(obj3.theString,obj3.theInt," ",obj3.newProperty," ",obj3.junk); // End hiding --> </SCRIPT> <P> Done. </BODY> </HTML> |
JavaScript 1.2 provides another way to instantiate objects. If you only need one object of a newly defined object type, and don't need to make provisions for instantiating additional objects of that type, an object initializer may be an appropriate way to go.
The syntax for creating an object using an object initializer is:
objectName = {property1:value1, property2:value2,..., propertyN:valueN} |
The following statement would create a simple object named myObj
having three properties named who, what, and where.
The initial values of the three properties are respectively: "Sue",
"went", and "home".
myObj = {who:"Sue", what:"went", where:"home"} |
myObj = {who:"Sue", what:"went", where:{morning:"work",evening:"home"}} |
An array Initializer allows you to create arrays in ways similar to
the creation of objects using object initializers. The syntax for
creating an array using an array initializer is as shown below
arrayName = [element0, element1, ..., elementN] |
Assigning the array to a variable name is optional.
You are not required to specify all of the elements in the array, but if you leave out any element specifications, you must provide the commas anyway to serve as placeholders. In this case, the value of the elements that you don't specify are undefined.
-end-