Saturday, December 29, 2018

5.3 Constructing Classes

While I have my January game ready, I am at my parent's place while the game is in a different city so I will not be posting it until January 2nd when I return to University.

JavaScript did not have "proper" classes until ECMAScript 6. The problem is that while there is now a class keyword that makes creating classes much easier in browsers that have an ECMAScript 6 complaint version of JavaScript, this is not all browsers. Eventually there will be so few browsers that do not support ECMAScript 6 that using JavaScript classes will make sense, but before that transition takes place, the old way of creating JavaScript classes must be used. The nice thing is that backwards compatibility means that the old way will still work on new browsers.

The ECMAScript 6 way of creating classes is with a class construct. Within this construct we have a constructor which initializes the class and then methods that the class knows. There is some special support for getter and setter methods which I will not be covering here as this book is more focused on older JavaScript but that may be something I cover in a future book. Here is what a soldier class would look like in ECMAScript 6 versions of JavaScript:

// General function for printing to the web page so results can be seen
// without requiring the console
function printTestLine(s) {
// we are grabbing an html element
var results = document.getElementById("testResults");
// now append the new line to this element
results.innerHTML = results.innerHTML + "
" + s

}

class E6Soldier {
constructor(name, rank, serialNumber) {
this.name = name;
this.rank = rank;
this.serialNumber = serialNumber; 
}

printNRS() {
printTestLine("Name: " + this.name + " Rank: " + this.rank +
" Serial Number:" + this.serialNumber);
}
}

printTestLine("ECMAScript 6 tests");
var soldier1 = new E6Soldier("Bob", "Private", 12345);
var soldier2 = new E6Soldier("Doug", "Captain", 23456);
soldier1.printNRS();
soldier2.printNRS();

You will notice that both soldiers simply used the E6Soldier class to build their object. The creation of an object from a class is called instantiation in object oriented terminology. Every object of a particular class is known as an instant of that class. Instances share the same properties and methods, though object specific properties and methods can be manually added to specific objects if desired, but are otherwise independent.

The old way of creating classes is similar to the new way but instead of grouping things into a class structure you are creating a function. This function sets up the properties just like the constructor above did and then sets up all the methods that are used by the class.

function Soldier(name, rank, serialNumber) {
this.name = name;
this.rank = rank;
this.serialNumber = serialNumber;

this.printNRS = function() {
printTestLine("Name: " + this.name + " Rank: " + this.rank +
" Serial Number:" + this.serialNumber);
}
}

Note that it is not necessary to have all the methods defined within the function. Some people actually like defining the methods of a class outside of the class. This is done by using the function's prototype, which is something we will be talking about in more detail in later sections.

Soldier.prototype.changeRank = function(newRank) {
this.rank = newRank;
}

Using the classes is pretty much the same the old way as it is the new way.

var soldier3 = new Soldier("Pete", "Private", 34567);
var soldier4 = new Soldier("Billy", "Captain", 45678);
soldier3.printNRS();
soldier4.printNRS();
soldier4.changeRank("General");
soldier4.printNRS();

The real power of classes comes from polymorphism and inheritance, but that is also where the biggest problems of object oriented programming come from. Next section we will start our exploration of polymorphism and inheritance.

Saturday, December 15, 2018

5.2 Creating Objects

There are a number of ways to create an object. The standard way of creating an instance of a class is to use the new constructor, which we will be covering in the next section. There is a special class that all classes are based off of called Object. This class can be used to create a new basic object which properties and methods can be attached to. To create an object using the new keyword is done as follows:

var myObj = new Object();

Properties can be added to an object by simply giving the property a value. This adds an interesting quirk to JavaScript programs as null indicates that an existing property has no current value attached to it while undefined means that the indicated property has not been attached to an object. For people use to typed languages this can be confusing as undefined and null are different things. You can check to see if a property is defined by using the following:

if (myObj.variable === undefined) 
// handle undefined variable here

Object Oriented programmers generally refer to functions that are part of an object as methods. As was discussed in Chapter 3, functions can be assigned to a variable. This means that to add a method to an object you simply need to add it as you would any other property. You can create a new function specifically for the object or you can use an already existing function and simply attach it to the object.

// here is a comomon function that will be shared by multiple objects
function printNRS() {
// we are grabbing an html element
var results = document.getElementById("testResults");
// now we are adding the info onto the text contained within the element
results.innerHTML += "
Name: " + this.name + " Rank: " + this.rank +

" Serial Number:" + this.serialNumber; 
}

// Build first soldier by using an object and adding properties to it
var soldier1 = new Object();
soldier1.name = "Bob"
soldier1.rank = "Private";
soldier1.serialNumber = 12345;

// Methods can be added too
soldier1.printNRS = printNRS;
soldier1.makeCaptain = function() { this.rank = "Captain"};

Notice that in order to reference a property of the object that is calling the function, the this keyword is used. Scope works a bit different than in most other languages and is function based. This is why the function printNRS can access the properties of the object as it is called from that object so holds the object's scope. We will come back to this topic in a bit more detail when we cover closures in a later section.

As mentioned earlier, there is more than one way of creating an object. JavaScript has a shorthand way of creating properties and pairing them to values so that it is easier to create objects with multiple properties initialized. This feature of JavaScript was expanded upon to come up with the JSON data transfer format which is why many people refer to creating objects using key : value pairs as being in JSON format. This shorthand method simply lets you define the contents of the object by using {} to indicate the object and then placing the property name followed by a colon followed by the value. It is possible to have functions within this declaration. Once the object is created you can add additional properties or method as you did with the soldier1 object. So, lets create a second soldier:

var soldier2 = { name : "Doug", rank : "Captain", 
serialNumber : 23456, 
makeMajor : function() {
this.rank="Major"

};
// adding addtional methods, such as this common method, is possible
soldier2.printNRS = printNRS;

JSON is an acronym and stands for JavaScript Object Notation. It was originally created as a data transfer standard between JavaScript and whatever language is being ran on the server-side. The idea is that objects get converted into strings to be transferred then converted into objects at the destination. It is much simpler and more condensed than XML so has largely replaced XML usage. If you are receiving JSON strings from a server or other input file you can easily convert the strings into JavaScript by using the built-in JSON class as is done to create our third soldier.

var soldier3 = JSON.parse('{ "name" : "Billy", "rank" : "General", "serialNumber" : 42}');
soldier3.printNRS = printNRS;

Manually creating multiple versions of what is essentially the same object does seem like a lot of work. There is a better way which we will cover in the next section.

Saturday, December 1, 2018

C5.1 Namespaces

When you are writing small programs you may never run into the namespace problem. Once you start using libraries, especially if you use multiple libraries, the namespace problem comes into play. Let us say you had a library that had a function for displaying hello. This library is called namespaceIssue.js and may look something like this:

message = "Hello!"
function sayHello() {
return message
}

Now lets say you wrote the following page that uses the library:

<!DOCTYPE html>

Namespace issue demo


Namespace issue demo









You would expect this program to display the words hello and goodbye. This is not what happens. Instead, it displays goodbye twice. Why? The library used the variable message to store the message that the sayHello function would display. The script in the html file uses message to store the goodbye message to display. It overwrites the variable which the library was using. For a small program like this it is a trivial problem to solve, but when the size of your program increases, especially if you are using code provided by third parties, this problem of variable (and function name) collision becomes a huge problem.

The solution to this problem is namespaces. The idea here is that you have a unique namespace for your program and all the variables for that program go into that namespace. Since each namespace is separate, you can have the same variable name in each of the namespaces without any conflict. In JavaScript, namespaces are created by creating a object with the name of the namespace. Here is the demo above re-written to use namespaces.

namespceUsed = {}
namespceUsed.message = "Hello World!"

function sayHello() {
return namespceUsed.message
}

It is possible to nest namespaces by having another namespace object as part of a namespace object. This is very commonly done to have library namespaces stored under a single unique namespace that you have control of. The convention is to use your domain as the unique name with appropriate names for the libraries under that domain. Some companies will take this a step further by having the root domain as the first namespace object, followed by their domain, followed by their library. This leads to the problem of declaring a namespace without overwriting other namespaces. The solution is to use the following way of declaring a namespace:

com = com || {}com.spelchan = com.spelchan || {}

It is a good habit to use namespaces for any script that you are loading. I generally don’t bother with the com root namespace but if Spelchan was a more common word, then it may be a good idea.