Tutorial — Creating New Objects

A Simple Class

Introduction

The traditional “first program” for a new language is the lowly “Hello, World!”. A “Hello, World!” program just runs and says “Hello”! Its purpose is to provide a simple way to illustrate and use the fundamental elements of a language.

For an Object-Oriented Programming Language (OOPL), such as JavaScript, “Hello, World!” can require designing a new class. (Even if not required, it's reasonable to design a new class as part of demonstrating any new OOPL.)

The standard “Hello, World!” class is the X,Y point class (such as might be used for graphs or any graphic software).

An XY Point class makes a good example, because it can be as simple–or as complicated–as the example requires. On this page, we'll start with a very simple example and progress to increasingly more complex examples. Each new version adds useful capabilities to the class.

Version 1

We start where the last page left off: with a Point() constructor function we use to create new Point objects. That version of the Point constructor takes x and y arguments used to initialize the x and y members.

function Point(x,y)
{
    this.x = x;
    this.y = y;
}
Version 2

The first improvement allows us to create new instances with none, one or both initialization arguments. New Points with no arguments set x and y to 0 (zero). New Points with one argument set both x and y set to the argument value. New Points with both arguments set x and y appropriately.

function Point(x,y)
{
    this.x = (x == undefined? 0: x);
    this.y = (y == undefined? this.x: y);
}

This version uses the ?: expression to check the argument and return an appropriate value. Arguments are only defined if the caller passes a value, so the expression compares an argument to the JavaScript keyword, undefined. The value for the new property comes from the argument, only if the argument is passed. Otherwise, it's assigned a default value.

The x member has a default value of 0 (zero). The default value for the y member is the x member's value. If the x defaults to zero, then so does the y member. If the x has a value, then that value is the y default value. The end result is that initializing no members results in setting both to zero. Initializing only x sets both members to that initial value, and initializing both set them to separate values.

NOTE: You could just as easily design Points where the y default is always 0.

The code fragment below shows the creation of four new Point objects. It also shows one way we might print the values of these objects. (Note the assumption of a Print() function.)

var p1 = new Point();
var p2 = new Point(10);
var p3 = new Point(21,0);
var p4 = new Point(21,42);

Print('p1=',p1.x,',',p1.y);
Print('p1=',p2.x,',',p2.y);
Print('p1=',p3.x,',',p3.y);
Print('p1=',p4.x,',',p4.y);

When run, the output is:

p1=0,0 
p2=10,10 
p3=21,0 
p4=21,42 

Version 3

The next version adds methods to the Point class. In this version, we define standalone functions as methods and bind references to those functions to new object instances. The methods, like the object constructor function, use this to access the object attributes.

We add two methods: Reset and Move. The first method resets the point to 0,0 (origin) coordinates. The second takes two arguments as new x,y coordinates.

function Point(x,y)
{
    this.x = (x == undefined? 0: x);
    this.y = (y == undefined? this.x: y);
    this.Reset = Point_Reset;
    this.Move = Point_Move;
}
function Point_Reset()
{
    this.x = 0;
    this.y = 0;
}
function Point_Move(x,y)
{
    this.x = x;
    this.y = y;
}

The code fragment below starts with the creation of a new Point object. It Print()s that value, Reset()s the Point and then Print()s it again. Last it Move()s the Point and Print()s its final value.

var p1 = new Point(21,42);
Print('p1=',p1.x,',',p1.y);

p1.Reset();
Print('p1=',p1.x,',',p1.y);

p1.Move(100,100);
Print('p1=',p1.x,',',p1.y);

When run, the output is:

p1=21,42 
p1=0,0 
p1=100,100

Version 4

The next version moves the separate method functions into the object constructor function. The end result is the same, we just don't have to worry about making up names for the functions or having them get accidentally separated.

function Point(x,y)
{
    this.x = (x == undefined? 0: x);
    this.y = (y == undefined? this.x: y);
    this.Reset = function () {
        this.x = 0;
        this.y = 0;
    }
    this.Move = function (x,y) {
        this.x = x;
        this.y = y;
    }
}

Because the change in this version is internal, we'd use it exactly the same as we'd use the previous version (so there's no usage code fragment).

Version 5

Our final version for this round adds a finishing touch: a nicer way to print the x,y values. Not only does this provide a cleaner way to print the object, it provides a traditional JavaScript way.

All JavaScript objects inherit a method, toString(), that returns a String representation of the object. JavaScript calls this method any time it wants to print an object. If you override toString(), you override the default print behavior of the object.

All that's required is providing a method, named toString().

function Point(x,y)
{
    this.x = (x == undefined? 0: x);
    this.y = (y == undefined? this.x: y);
    this.Reset = function () {
        this.x = 0;
        this.y = 0;
    }
    this.Move = function (x,y) {
        this.x = x;
        this.y = y;
    }
    this.toString = function ()
    {
        return 'Point:x,y=' + this.x + ',' + this.y;
    }
}

The code fragment below creates two objects and Print()s them.

var  p1 = new Point(10,10);
var  p2 = new Point(19,21);

Print(p1);
Print(p2);

p1.Move(100,100);
p2.Reset();
Print(p1);
Print(p2);

When run, the output is:

Point:x,y=10,10 
Point:x,y=19,21 
Point:x,y=100,100 
Point:x,y=0,0