JS as an Object Oriented Language

One of the main archetypes of programming for computer science is the idea of an "object oriented language".

An Object Oriented Design places emphasis on constant data fields and reusable objects which are managed by procedural action (as opposed to a monolithic procedural routine that applies a single list or tree of actions).

The structure of JavaScript does not naturally lend itself to Object Oriented programming very well. It is capable of it, but the original design of JavaScript did not include way of creating instances as you might recognize them in other languages. It was only through the looseness of the language and a lack of strict type checking that instances were hammered into it. But you might be wondering what is meant by an "instance."

An Instance is any encapsulated code whose structure, properties, and methods are based on a separately designed prototype, but with values unique to that instance

Instances typically only exists at run time. This means that you will never fully write out an instance. You will write out the code the instance is based on but once made the only thing within it you should change are the values within the instance.

This is not unlike the way a function can be called multiple times after it has been written out once. Only in the case of object instances the called code itself takes on a perpetual state until destroyed by either the user or a managed garbage collector.

There are a few ways to create this reusable code within JavaScript. Let's restrict yourself the three main approaches below.

Functions as Objects

Using functions as objects that can be copied and made unique is one of those uncomfortable qualities of JavaScript that might confound some programmers coming from another language. Typically treating a function as if it were a date *type* is not something you'd do in languages like C++.

In JavaScript it's acceptable to write code like this...


var myFunction = function(){};

This is what is referred to in JavaScript as an "anonymous function". It can also be called an "expression".

An anonymous function is a function without a name that is referenced by a variable and can be used as a variable.

An expression is code made up of several smaller pieces of code that can be referenced to get a single value.

In JavaScript what this means is that if, for whatever reason, you want to "hold" a function in a particular state as if frozen in time you can do so. This allows you to run a function, but retain the information made within the function when run, and then use the function again with those changed values.

This means functions can essentially be made into instances of themselves. Here's an example.


<script>

// First lets make a boolean to demonstrate something about function instancing 
// later on in our code.
var counting_test = 0;

// Establish the original prototype / container.
function Function_Example( a_ ){
    this.value_a = a_;
    this.value_b = "john";
    this.value_c = "doe";
    this.inner_fun = function() {
        return this.value_b + ' ' + this.value_c;
    };
    counting_test++;
}

// Instance the prototype / container.
var test_f_1 = new Function_Example( 2 );
var test_f_2 = new Function_Example( 4 );

/*
So what is the process here?  We've established a template for our function and
then created two variables that in turn create two new instances of that
function.  From the point of view of the author the process is complete.  But
within a computer things are seen differently.  For each new instance the
function is copied, the argument is applied as if it were being run, and the
name can be considered to be changed to the name of the variable.

Below is code "similar" to what the computer itself might now see from its own 
point of view.

function test_f_1( a_ ){
    this.value_a = 2;
    this.value_b = "john";
    this.value_c = "doe";
    this.inner_fun = function() {
        return this.value_b + ' ' + this.value_c;
    };
}

function test_f_2( a_ ){
    this.value_a = 4;
    this.value_b = "john";
    this.value_c = "doe";
    this.inner_fun = function() {
        return this.value_b + ' ' + this.value_c;
    };
}

Just keep in mind that this DOES NOT mean that we can "run" the variable.  It 
is still a variable that holds a reference to information.  It is not a 
function itself and as such can not be run with a command like "test_f_1();".

Let's get information from these instances to see what they hold.
*/

console.log( "Function instance 01: " + test_f_1.value_a );
console.log( "Function instance 02: " + test_f_2.value_a );
console.log( "Function instance 03: " + test_f_2.inner_fun() );

/*
Upon running the above code the above will return the following lines...
2
4
john doe

We can also see that each time we instantiate the function as a new copy we are 
in fact running the code.  Note how the function had the line to increment 
"counting_test" by one integer.  At the end of our code "counting_test" now has 
a value of "2" because we made two instances of the function and in doing so 
ran the function as it was created.  We can see that with one more test...
*/

console.log( "Function count test: " + counting_test );

/*
In this way, when creating a new copy of a function prototype, the
function itself serves as its own "Constructor".  This is a common
concept in most programming languages and will be explained more in
the "Class" version of object instantiation below.
*/
</script>

Objects as Objects

How to create and use JavaScript Objects is detailed in a previous section. Let's look at how to create copies that can work independently from the original .

What's important to keep in mind about this method is that it turns our initial object in a prototype similar to the function prototype above. This is similar to class inheritance in other languages in that it is NOT "cloning" the object but is allowing the new object to base current properties / structures on the properties and structures of the referenced object.

Since an object is essentially a container of information you can not use arguments / parameters as you could with a function on the object itself.

You CAN however, establish normal arguments for the function defined within an object.

This doesn't mean that you can't change the original, you can, but it should probably be best to not reference the original prototype directly for usage and instead always make sure to create a new object when needed.


<script>

// Establish the original prototype container.
var Object_Example = {
    value_a: 2,
    value_b: "john",
    value_c: "doe",
    inner_fun : function() {
       return this.value_b + ' ' + this.value_c;
    }
};

// Instance the container.  The easiest way to do this is to make use of the 
// "create" method that is an inherent JavaScript method (type it exactly!).
var test_o_1 = Object.create( Object_Example );
var test_o_2 = Object.create( Object_Example );

// Since objects are not functions that can have arguments
// into them we have to assign new values AFTER the new copy
// has been made.
test_o_1.value_a = 4;
test_o_2.value_a = 6;

console.log( "Object instance 01: " + test_o_1.value_a );
console.log( "Object instance 02: " + test_o_2.value_a );

// Returns...
// Object instance 01: 4
// Object instance 02: 6

// We can access functions listed in objects much the
// same way we do in function prototypes.
console.log( "Object instance 03: " + test_o_1.inner_fun() );

// Returns...
// Object instance 03: john doe

// And to show that the new object is in fact a new instance.
Object_Example.value_a = 333;

console.log( "Object original: " + Object_Example.value_a );
console.log( "Object instance 02: " + test_o_2.value_a );

// Returns...
// Object original: 333
// Object instance 02: 6

</script>

Classes as Objects

Classes will be beneficial in that they allow you to write JavaScript in a way that is closer to conventions of other programming languages. This is a double edged sword of course because that means things like functions are written out differently within the class object then they would be if they weren't in a class. Whether or not to adopt this format is up to the author at this time.

As of the time of this writing the concept of classes within JavaScript is still considered to be experimental and may not be supported by all browsers. To use them in browsers like Chrome or Firefox you will need to enable a "Strict" mode in your JavaScript code. This can be done easily be adding the line "use strict;" to the beginning of your code. You probably saw it at the very beginning of this page to ensure that all later code ran appropriately. When Classes become fully approved by the powers that be this line will no longer be needed.


<script>

// Invoke the "strict" command to tell the client browser that we want to be 
// able to use the code further down.
// It needs to be written exactly as is seen, with quotations.
"use strict";

// Here we create our class object.  It only needs the keyword "class" and the
// class name to work.
class Class_Example {

    // Within a class you have the option of writing a "constructor".  A
    // constructor contains code that is run whenever an instance in made.

    // Unlike other languages the constructor in a JavaScript class is NOT the
    // same name as the class itself but simply uses the keyword "constructor".

    // You can, however, establish whatever parameters can be sent within the
    // constructor you like.
    constructor( name, surname ) {
        this.value_a = 2;
        this.value_b = name;
        this.value_c = surname;
    }

    // This is how you'll establish properties within your class.  We can not 
    // put variables here within the class like you might 

    // We can also store functions within the class in any format we like.
    inner_fun(){
        return this.value_b + " " + this.value_c;
    }
}

// Making new instances of a class is easy, we just need to use the "new" 
// keyword and the name of a class when assigning a new variable.
var test1 = new Class_Example( "John", "Doe" );
var test2 = new Class_Example( "Jane", "Doh" );

// And, because JavaScript is so lenient, even add new properties to the class.
test2.height = 4;

// We can now access the individual properties established by the class.
console.log( test1.height );
console.log( test2.value_a );

console.log( test1.inner_fun() );
console.log( test2.inner_fun() );

/*
The above returns the following into the console...

undefined
2
John Doe
Jane Doh

*/
</script>