Page 1 of 1

Intro to Object Oriented Javascript Rate Topic: -----

#1 BetaWar  Icon User is online

  • #include "soul.h"
  • member icon

Reputation: 1107
  • View blog
  • Posts: 6,925
  • Joined: 07-September 06

Posted 15 September 2008 - 03:42 PM

As of late I have seen a lot of questions about Javascript that could be easily done with some Object Oriented programming, so I decided to write a short tutorial on it.

In this tutorial
We will be creating 2 objects, 1 called Dice and the other called Thrower. The Dice class will be an object that can be set with a naximum number of sides and rolled to get a number. The Thrower object will take multiple dice and roll them all at once returning the resultant sum of all the dice rolled.

Lets get started
When starting out creating an object it is useful to know what the object will need. FOr instance, you wouldn't want to give the object Air a variable called breathing_rate, so make sure you have thought your object through before creating them.

A note about coding - To continue, or begin creating good programming habits we will be naming all objects with a capital letter. As you saw with the Air object the "A" is capitalized. This is because it is the standard for the time being. For anyone who has programmed in Java, Actionscript, C++ or any other number of languages you know that this is the case, and has been for quite a while. Later on, when we startcreating sub-functions we will be maning them starting with lower case and then using camel case for new words. That looks like so: getNum

So, to get started with our code we create a function called Dice (this will be our object), and we give it these 2 variables: number and max. This code looks like so:

function Dice(){
  this.number;
  this.max;
}


NOTICE - When using variables that are for an object you must use this otherwise the variables are deleted after they are done being used. This is of course unless they are global, but we don't want to have a whole bunch of global variables.

Because we want to be able to set the max we need to add a parameter to Dice that is set to max:

function Dice(maxNum){
  this.number;
  this.max = maxNum;
}


Now, however we have a problem. What if someone doesn't set the max?
This can easily be checked for by and if/ else statement:

function Dice(maxNum){
  this.number;
  if(maxNum){
	this.max = maxNum;
  }
  else{
	this.max = 6; //some initial value, in this case a 6 sided dice.
  }
}


Good, now that we have the basics of our object complete lets start adding some sub-functions (methods in Java, class functions in C++).

Adding functions
Adding functions to an object is a little different than in other languages. This is because it is done inside of a function and acts like a sub-function.

This can be seen as such:

function Dice(maxNum){
  this.number;
  if(maxNum){
	this.max = maxNum;
  }
  else{
	this.max = 6; //some initial value, in this case a 6 sided dice.
  }
  this.roll = function(){
	// Do stuff here
  }
}


In the case of our roll function we will want to have it calculate a random number between 1 and its max. THis is accomplished like so:

function Dice(maxNum){
  this.number;
  if(maxNum){
	this.max = maxNum;
  }
  else{
	this.max = 6; //some initial value, in this case a 6 sided dice.
  }
  this.roll = function(){
	this.number = Math.round(Math.random()*(this.max-1))+1;
	return this.number;
  }
}


Which simply gets a random number (returns a number between 0 and 1), multiplies it by 1 less than max, rounds it to the nearest int, and adds to it. Adding 1 sets the minimum the number can be as 1.

NOTICE - The function returns the number that is calculated.

Now, just because we have returned a number once doesn't mean that we can just let it sit there until we roll again. What if someone wants to take another look at the number?

In that case we will need to let them see it. This is done by creating another sub-function called getNum.

PARTICIPATION OPP! - If you feel like trying out some coding on your own for this object create a sub-function that returns the number of the object. If you don't care to try things on your own at this point continue reading.

So, now that you have made up your mind, here is the current code:

function Dice(maxNum){
  this.number;
  if(maxNum){
	this.max = maxNum;
  }
  else{
	this.max = 6;
  }
  this.roll = function(){
	this.number = Math.round(Math.random()*(this.max-1))+1;
	return this.number;
  }
  this.getVal = function(){
	return this.number;
  }
}


Creating a Thrower
PARTICIPATION OPP! - For those of you who feel like trying more OOJS on your own here is your chance to try creating an object on your own! The object name is Thrower and will take an array (or single) dice, be able to roll all the dice, returning the sum of all the rolled dice; and add extra dice to the array.

Now, we will be creating another object. This will be able to control the dice objects (in a sense of the word).

Starting out we will create the object:

function Thrower(){
  // Stuff here
}


To start out the Thrower function will need the variable myDice. After that is complete we need to get a function to roll the dice created.

For the moment the code looks like so:

function Thrower(dice){
  this.myDice = dice;
}


When creatingthe roll function it is important to remember that we need to have it loop through the whole length of the array this.myDice. We also want it to return the sum of the dice, this means we need to have it counting through the loop.

Here is what the thrower object looke like with the roll functuion:

function Thrower(dice){
  this.myDice = dice;
  this.roll = function(){
	var sum = 0;
	for(var i=0; i<this.myDice.length; i++){
	  sum += this.myDice[i].roll();
	}
	return sum;
  }
}


Now, what do we do if people want to add more dice?
This is easy enough, you add to the end of the array this.myDice with a simple function called addDie

Here if the final code for the Thrower object:
function Thrower(dice){
  this.myDice = dice;
  this.roll = function(){
	var sum = 0;
	for(var i=0; i<this.myDice.length; i++){
	  sum += this.myDice[i].roll();
	}
	return sum;
  }
  this.addDie = function(dice){
	this.myDice[this.myDice.length] = dice;
  }
}


Creating instances of an object
When creating instances of an object it is important to remember that you need to use the new keyword.

Here is a code snippet we can use to create a single instance of a Dice:

var dice = new Dice();


REALIZE - You can call to all the functions and variables inside of the object instance like so dice.(FUNCTION/VARIABLE NAME HERE). So, if we were to call dice.roll() it would roll the instance of the object that the variable dice is pointing to.

The Finished Product!!!
Here is a look at the whole code that will output the number and everything:

function Thrower(dice){
  this.myDice = dice;
  this.roll = function(){
	var sum = 0;
	for(var i=0; i<this.myDice.length; i++){
	  sum += this.myDice[i].roll();
	}
	return sum;
  }
  this.addDie = function(dice){
	this.myDice[this.myDice.length] = dice;
  }
}
function Dice(maxNum){
  this.number;
  if(maxNum){
	this.max = maxNum;
  }
  else{
	this.max = 6;
  }
  this.roll = function(){
	this.number = Math.round(Math.random()*(this.max-1))+1;
	return this.number;
  }
  this.getVal = function(){
	return this.number;
  }
}

var dice = [new Dice(), new Dice()];
var hands = new Thrower(dice);
  hands.addDie(new Dice());
for(var i=0; i<100; i++){
  document.write("Dice roll "+(i+1)+" = "+hands.roll()+"<br>");
}


The End
Enjoy your additional knowledge.

Is This A Good Question/Topic? 1
  • +

Replies To: Intro to Object Oriented Javascript

#2 ronaaronson  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 6
  • Joined: 08-March 09

Posted 08 March 2009 - 09:17 AM

I would like to point out an alternate way to add methods to an object, which are function properties of an object. I also would like to expand on the javascript keyword this:

Whenever any function is invoked, this is set to be a reference to the "current" object. When the function invoked as a "standalone" function, the current object is the global object, which is actually the window object when the script is running in a browser. But when the function is invoked with the new operator, this is set to reference the newly created object. Similarly, when you invoke a function via an object reference, this will refer to that object:


<script>

function Thing(param)
{
	this.x = param; // what does "this" refer to?
	this.showX = function() {alert(this.x)}
}
Thing(9); // "this" will refer to the global object, which is the window object
alert(window.x); // 9
alert(x); // 9 
showX();  // 9: function showX has been added to the global object

var thing1 = new Thing(5); // a new object (thing1) will be allocated and "this" will refer to it when the Thing function executes 
alert(thing1.x); // 5
thing1.showX();  // 5: "this" will refer to thing1 when showX executes

</script>



Now if I were two create to Thing objects:

var thing1 = new Thing(1);
var thing2 = new Thing(2);



then thing1 and thing2 will have their own x properties, which is what you would want. But each Thing will also have a showX property that points to the same identical function. Imagine if the Thing function assigned to this dozens of function properties and we created dozen of Thing objects. This would not be very efficient.

As it turns out, every function, which is actually a type of object, has a property named prototype that by default refers to an empty object. Well, not exactly empty. The prototype object has one property named constructor that refers back to the function:

function Thing()
{
	this.x = param; // what does "this" refer to?
	this.showX = function() {alert(this.x)}
}

alert(Thing.prototype.constructor == Thing); // true



When you create a new object by invoking the Thing "constructor" function, the newly created object is assigned an internal property that refers to the constructor's prototype object. This property is actually not accessible to user code, but let's suppose it has the internal name __proto__:

var thing1 = new Thing(1);
/*
if we could access the internal property we would have:
thing1.__proto__ == Thing.prototype; // true
*/



Whenever any property of an object is referenced and not found by the javascript processor, javascript looks at the object referred to by its internal __proto__ property to see if the property is defined there. If not, the search continues by looking to see if that prototype object has a __proto__ property of its own and continues the search up the "prototype chain". We can say that an object "inherits" properties from its prototype object. So the prototype object is the perfect place to store properties that are to be shared among all instance objects:

function Thing(param)
{
	this.x = param; // what does "this" refer to?
}
Thing.prototype.showX = function() {alert(this.x)}

var thing1 = new Thing(1);
thing1.showX();  // showX is found in Thing.prototype



The above technique is not only more efficient, but it allows for more robust creation of subclasses via inheritance, which is another discussion altogether.
Was This Post Helpful? 0
  • +
  • -

#3 noyesa  Icon User is offline

  • New D.I.C Head

Reputation: 5
  • View blog
  • Posts: 27
  • Joined: 01-April 09

Posted 01 April 2009 - 07:35 PM

ronaaronson has touched on probably the most important concept of object-oriented programming (OOP) in Javascript -- the Prototype chain. Prototypal inheritance is a confusing subject for programmers who are used to the Classical approach to creating objects in other programming languages, like Java and C++. In addition, most other programming languages used on the web, like PHP and Python, also use Classical OOP

Prototyping is elegantly simple, and is part of what makes OOP in Javascript so expressive. You can do a lot more with fewer lines of code in Javascript than you can in other languages, owing entirely to the fact that all objects in Javascript inherit their properties and methods from other objects. At the top of this chain is the Object object.

I could spend all day discussing which object-oriented paradigm is superior and we would never reach a conclusion, since each has its strengths and weaknesses.

While I highly recommend that if you're coming from another language you take the time to familiarize yourself with Prototypal Inheritance, it is not my goal here to convince you to use it. I personally think it's best to use Prototypal Inheritance, but I will not deny that there are many scenarios where a classical approach is beneficial, particularly when working in a team. The Class, the heart of classical OOP, can be functionally simulated in Javascript.

The Constructor
Creating a class in classical OOP is an iterative process whereby you continually modify your class throughout the development of your program or script. However, there is one key component that every class needs: a constructor.

In Javascript, the constructor is a blueprint for building an object. It tells the Javascript interpreter what values (variables), which are called object members in OOP, that the new object will contain, and sets default values. Without further ado, here is an example of a constructor:

function MyClass(num) {
    this.num = num;
}

Of course, this can be seen in the above tutorial. What I'm going to introduce here is the concept of access modification, whereby we designate that certain object members can only be touched by object methods, as opposed to allowing the script to interface with object members directly, using the syntax myObject.myValue.

Object members and methods that can be called directly are said to be public. On the flip side, objects and members that can only be referenced from within the object itself are said to be (you guessed it) private.

Languages that implement a well-defined classical approach to OOP will have the keywords public and private. These keywords are called access modifiers. For example, in PHP5, to declare a public member called $myNum, you would do something like this:

<?php 
    class MyClass {
        // Public member
        public $myNum;

        // Class constructor
        public function __construct($num) {
            $this->myNum = $num;
        }
    }
?>

Javascript posseses no such access modifiers. They are instead implicit; we can simulate the functionality of access modifiers by exploiting Javascript's unique scoping.

Function Scope
If you're used to programming in languages like C, you're probably inclined to block scope, where any variables that are declared within a block are destroyed once the block scope is complete. Consider the following C program:

#include <stdio.h>

int main() {
    int myInt = 1;
	
    for (int i = 0; i < 10; i++) {
        int temp = i + myInt;
        printf("The value of temp is %d.", temp);
    }
	
    printf("The value of temp is %d.", temp);    // Generates compiler error because temp isn't declared in this scope

    return 0;	
}

The variable temp is declared within the for-loop block. Once that loop finishes execution, the block scope is terminated and the variable is deleted. It cannot be accessed from the next level up, the main() function.

On the flip side, let's take a look at how Javascript handles this:

function sillyFunction() {
    var myInt = 1;

    for (var i = 0; i < 10; i++) {
        var temp = myInt + i;
        alert("The value of temp is " + temp);    // Outputs 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
    }

    alert("The value of temp is " + temp);    // Outputs 10
}
sillyFunction();

As you can see, in Javascript, it doesn't matter where in the function you declare a variable, be it nested in a block or in the root function block, so long as you've declared the variable before you attempt to use it. For this reason, the following code is functionally equivalent to the last:

function sillyFunction2() {
    var myInt = 1, i, temp;

    for (i = 0; i < 10; i++) {
        temp = myInt + i;
        alert("The value of temp is " + temp);
    }

    alert("The value of temp is " + temp);
}

There are actually very good reasons for declaring all of your variables in one line, namely for debugging purposes. If you declare all of your variables in one spot, there's no hunting through your program to find what value you initialized that variable at.

Private, Public, and Privileged Methods
Using this unique scope, we can create methods that are both accessible to everyone, and have access to private variables. Here's a constructor with a private variable and a public method:

function MyConstructor() {
    var num = 1;    // Private variable
}

// Public method
MyConstructor.prototype.getNum = function () {
    return this.num;    // Gah! this.num doesn't exist!
}

"But wait", you're thinking, "we didn't assign num as a member using the this keyword. It doesn't exist." It is true that in its present form, getNum won't work, however it is a misconception to think that num doesn't exist. num will continue to exist until the object is destroyed, it just isn't accessible from the outside. However, think about the function scope that I just discussed. Because Javascript uses function scope, any blocks contained within the MyConstructor function has access to variables declared in MyConstructor. If we re-engineer our getNum method like this...

function MyConstructor() {
    var num = 1;
    this.getNum = function () {
        return num;
    };
}

Because of the function scope, getNum has access to the private num variable, which is local to MyConstructor. getNum is said to be a privileged function.

In the above two posts, you are presented with two ways of creating public methods. You've just learned that one of them, declaring methods from within the constructor using the this keyword actually creates a privileged method. I won't cover those in any more detail. There is only one more piece to the OOP puzzle:

function MyConstructor() {
    // Private variable
    var num = 1;

    // Private method
    function addOne() {
        return num + 1;
    }

    // Privileged method
    this.getNumPlusOne = function () {
        return addOne();
    };
}

When to use private, privileged, and public variables is at your discretion. I'm leaving out a lot here, so it's up to you to look into a general approach to classical OOP. In doing so you will learn how to create classes, and how to choose whether a method should be public or private.
Was This Post Helpful? 0
  • +
  • -

#4 GMorris  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 15-June 09

Posted 20 June 2009 - 09:24 AM

On the this.roll function in Thrower, the code was running three times and giving me rolls from 4 to 15 or so most of the time, so I changed it to this:

for(var i=1; i<this.myDice.length; i++)


Other than that, I learned a little more about Javascript and using objects. It just never seems to occur to me that you CAN, since I mostly just write small programs most of the time anyway.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1