Browser Scripting, Page 2

Release: 2010-07-20
Jump to Web Standards Articles TOC

, Page 2

Objects

Another way of variables with multiple pieces of related information are objects. Unlike compiled languages, objects in ECMAScript are prototype-based: variables that you add simple scalar variables or arrays as properties of the object and functions that you add as methods of the object, all at runtime.

For instance assume we have created a product object with name, mainColour and dimensions properties:

myProduct1.name = "truck";
myProduct1.mainColour = "blue";
myProduct1.dimensions["width"] = 108;
myProduct1.dimensions["height"] = 68;
Figure 13: An object with properties

Creating an object can be done in one of two ways either by creating the structure of the object via a function using the this keyword and then assigning the special function to a variable as an object using the new keyword:

function Product (name, mainColour, dimensions) {
  this.name = name;
  this.mainColour = mainColour;
  this.dimensions = dimensions;
} // (Object Definition) Product

var prodDim["width"] = 108;
prodDim["height"] = 68;

var myProduct1 = new Product("truck", "blue", prodDim);
Figure 14: Creating an object via a function.

Or since JavaScript 1.2 and ECMAScript Edition 2 you can use object initialisers using braces and property names as names, numbers or strings and their values:

var myProduct1 = {
  name: "truck",
  mainColour: "red",
  dimensions: [108, 68]
} // (Object) myProduct1
Figure 15: Creating an object via object initialisation.

After creating an object you can add an extra property simply for instance myProduct1.group = "model"; but this would only add this property and value specifically to the myProduct1 object and not any other objects based on Product.

To add a new property to a pre created object definition you use the prototype property:

Product.prototype.group = null;
myProduct1.group = "model";
Figure 16: Adding more properties to pre created object definitions

This adds the group property to all objects based on Product.

To delete properties from object instances such as myProduct1.group you use the delete keyword as delete myProduct1.group would delete the group property. Also delete myProduct1 would delete the whole object if the object variable was not created with var.

Adding methods to an object is done by creating a function as usual and the same way you add a property to the object but using the function name as the value of the property making it a method.

function objLabel () {
  return "This product is a " + this.name + " and it's main colour is " + this.mainColour + ". The product's dimensions are " + this.dimensions["width"] + " by " + this.dimensions["height"] + ".";
} // (Method) objLabel

function Product (name, mainColour, dimensions) {
  this.name = name;
  this.mainColour = mainColour;
  this.dimensions = dimensions;
  this.toLabel = objLabel;
} // (Object Definition) Product
Figure 17: Adding an object method

Then you can use myProduct1.toLabel(); which will return "This product is a truck and it's main colour is blue. The product's dimensions are 108 by 68.".

There is a collection of predefined core objects available to use. Some of these include:

String Objects

To create a string object you use the new keyword as var s1 = new String("The BluE box");.

String objects have a property called length that provides how many characters are contained in the string. s1.length; would provide the number 12 as there are 12 characters including spaces in the string.

Two of the string methods are toUpperCase() and toLowerCase(). Such as s1.toLowerCase(); would provide "the blue box".

Providing a part of the string is done using the substring() method. There are 2 parameters for this method: the first is the zero-based index of the character starting the string part such as the first character in the string is zero, the second is 1. The optional second parameter is the index of the character ending the string part; if higher than the first parameter, then the substring is from the first parameter's character and towards the right of the string. If the second parameter is lower than the first then it is from the first parameter's character and towards the left of the string.

s1.substring(0, 1); returns "T".

s1.substring(1, 5); returns "he B".

s1.substring(6, 0); returns "The Bl".

 Also the substr() method is pretty much the same.

 You can split strings with the split() method with the separator string as the first parameter and an optional number as the second parameter. The separator string is found in the main string and separates the substrings before and after each instance of the separator string; the second parameter is how many instances of the separator string is searched for. An array is the result of the split() method.

 Joining string objects together can be accomplished by the concat() method with a comma separated list of string objects.

 The replace() method allows you to do search and replace abilities such as replace 'tin' with 'tan':

var txt = new String("This tin has changed colour");
var txt2 = txt.replace("tin", "tan");
Figure 18: search and replace with String

Number Objects

The Number Object has some constants that you use literally such as:

 Number.MIN_VALUE which provides the minimum value possible;

 Number.MAX_VALUE provides the highest value possible;

 Number.NaN provides a special Not-A-Number value;

 Number.POSITIVE_INFINITY provides the value that represents Infinity at the positive perspective;

 Number.NEGATIVE_INFINITY provides the value that represents Infinity at the negative perspective.

Objects created from the Number Object or a number literal in a variable can use some Number methods.

var num1 = 28;
var num2 = new Number(489);
Figure 19: Creating more numbers

Using the toString() method returns the number as a string in the typical decimal form by default. You can provide a number between 2 and 36 as the parameter to change the output format such as 2 for base 2 (binary), 8 for octal (0-7), 10 for decimal (0-9) or even 16 for hexadecimal (0-9 a-z / A-Z).

 To control how much precision is used when returning a decimal number you use the toPrecision() method. With a number from 1 to 21 by standard (some implementations may support higher precisions) as the parameter will return the decimal to that number of significant digits.

// Returns 3.9283;
var num3 = 3.92828739278;
num3.toPrecision(5);

// Returns 39.283;
var num3 = 39.2828739278;
num3.toPrecision(5);
Figure 20: Number precision

Without a parameter the toPrecision() method just returns the exact number.

Array Objects

Arrays can be created via the Array Object, such as:

var fruit = new Array("orange", "apple", "grape", "banana", "pear");
var fruit2 = new Array(5);
Figure 21: Array objects

The second example creates an array with 5 empty array elements. Populating the empty array objects is done the same way you populate normal arrays.

 A main array property is the length such as fruit.length; will provide the number of array elements in the array.

Joining multiple new array elements with an existing array you have a comma separated list of array elements as the parameters of the concat() method. The join() method uses a 'joiner' string parameter and joins each array element together with the 'joiner' string between each element and the results in a simple string. If the 'joiner' is left empty then the comma (,) character is used.

 Also a method for reversing the contents of an array just by using the reverse() method. Ascending sort for an array contents is done via the sort() method.

Date Objects

Handling dates and times is done via the Date Object.

var now = new Date();
var then1 = new Date("August 25, 2008 14:18:02");
var then2 = new Date(2008, 08, 25, 14, 18, 02);
var then3 = new Date(2008, 08, 25);
Figure 22: Date Objects

Without any parameters, the date object selects the current date and time.
With a full month name followed by a space and the day number, a comma, the full year number, a space and the time in hours, a colon, minutes, colon and seconds (a UTC Time) will select that date and time and put that into the date object variable. Alternatively you can have comma separated parameters of the year, month, day and optional hours, minutes and seconds all as numbers.

 Date methods include get based methods that have no parameters and set based methods that have a single parameter of the particular time piece to set:

  • getDate() / setDate() returns / sets the local day of the month (1 to 31),
  • getDay() returns the local day of the week (0 for Sunday to 6 for Saturday) (there is no setDay as this is done automatically),
  • getFullYear() / setFullYear() returns / sets the local 4 digit year,
  • getMonth() / setMonth() returns / sets the local month (0 for January to 11 for December),
  • getHours() / setHours() returns / sets the local hour (0 to 23 (24 hour clock) ),
  • getMinutes() / setMinutes() returns / sets the local minutes (0 to 59),
  • getSeconds() / setSecons() returns / sets local seconds (0 to 59) and
  • getMilliseconds() / setMilliseconds() returns / sets local milliseconds (0 to 999).

 There are Coordinated Universal Time (UTC) versions of the above date methods as getUTCDate(), setUTCDate(), getUTCDay(), getUTCFullYear(), setUTCFullYear(), getUTCMonth(), setUTCMonth(), getUTCHours(), setUTCHours(), getUTCMinutes(), setUTCMinutes(), getUTCSeconds(), setUTCSeconds(), getUTCMilliseconds() and setUTCMilliseconds().

 Also getTime() / setTime() returns / sets the date and time as a number representing milliseconds since midnight, January 1st , 1970 UTC (Computer Epoch) and getTimezoneOffset() returns the current locale's timezone in minutes.

 A couple of obsolete methods: getYear() and setYear() returns and sets the year only with 2 digits. These two are still supported for backwards compatibility but should not be used any more. Use the full year and UTC full year get and set methods instead.

Math Objects

The Math object is used literally such as Math.PI rather than using new and putting into a variable. This object provides typical math constants as properties such as:

 Euler's Constant (Math.E),

 Natural Logarithm of 2 (Math.LN2) or 10 (Math.LN10),

 Logarithm Base 2 (Math.LOG2E) or 10 (Math.LOG10E),

 PI (Math.PI),

 Square root of 2 (Math.SQRT2) and 1 over the square root of 2 (Math.SQRT1_2).

 Plus typical math functions as methods such as:

 Math.abs() takes a number and provides the absolute number of it such as Math.abs('-5'); provides 5;

 Math.sin(), Math.cos(), Math.tan() each take a number (in radians) and provide either the sine, cosine or tangent respectively;

 Math.asin(), Math.acos(), Math.atan() each take a number between -1.0 and 1.0 and provide either the arcsine, arccosine or arctangent respectively (in radians);

 Math.atan2() takes a y-coordinate as the first parameter and an x-coordinate as the second parameter and provides a value between -Pi and Pi in radians;

 Math.exp() takes a number as the exponent for Euler's Constant;

 Math.log() takes a number and returns the Natural Logarithm of that number;

 Math.round() takes a number and rounds it to the nearest integer: if .5 and higher decimal then rounds up or below .5 decimal then rounds down;

 Math.ceil() for ceiling provides the smallest integer greater than or equal to the number parameter (in other words always rounds up);

 Math.floor() provides the highest integer less than or equal to the number parameter (in other words always rounds down);

 Math.min() provides the smallest number out of the comma separated list of number parameters;

 Math.max() provides the highest number out of the comma separated list of number parameters;

 Math.pow() takes a base number as the first parameter and an exponent or power number as the second parameter and returns the result of base to the power of exponent;

 Math.random() has no parameters, just returns a random number from 0.0 to below 1.0 and is seeded by the current datetime;

 Math.sqrt() provides the square root of the number parameter.

Flow Control

Flow Control includes loops such as for, while and conditions such as if...else and switch.

Looping with for allows you to sequence through a known range such as from 1 to 200. You first set a variable (usually i or j) with the starting number, set the same variable to be less than (<) the highest number plus one followed by the same variable to be incremented (++). Or instead of less than you may use less than or equal to (<=) the highest number. Also decrements can be set too (--).

for (i=1; i<201; i++) {
  // Set commands to process for each incrementation.
}
for (i=1; i<=200; i++) {
  // Set commands to process for each incrementation.
}
for (i=200; i>0; i--) {
  // Set commands to process for each decrementation.
}
for (i=200; i>=1; i--) {
  // Set commands to process for each decrementation.
}
Figure 23: Looping with for

Looping with while allows the instructions to action only during a condition's lifetime:

while (flipSwitch == "on") {
  // Do this
}
while (flipSwitch != "off") {
  // Do this
}
Figure 24: A while loop

Also a condition as 'if this, otherwise that' can be done for instance:

if (setting=="level 2") {
  // Do this
} else {
  // Do that
}
Figure 25: If...else condition.

Multiple conditions:

if (setting=="level 2") {
  // Do this
} else if (group=="lower") {
  // Do this instead
} else if (flipSwitch=="on") {
  // Or do this
} else {
  // Or do that
}
Figure 26: If...else..if condition.

A switch is like an if...else...if with the variable having the same name in each condition for instance an if...else...if such as the following can also be a switch statement as the following:

// The if...else...if
if (setting=="level 2") {
  // Do this
} else if (setting=="level 5") {
  // Do this instead
} else if (setting=="level 28") {
  // Or do this
} else {
  // Or do that
}

// The switch
switch (setting) {
  case "level 2":
    // Do this
    break;
  case "level 5":
    // Do this instead
    break;
  case "level 28":
    // Or do this
    break;
  default:
    // Or do that
}
Figure 27: Switch condition.

The value of each case is usually a number or a string. The break keyword is used to break out of the loop or condition. As in the case of switch (pun half intended): if the first case did not have the break keyword then if setting was 'level 2' then it would process the commands for both 'level 2' and 'level 5' but not 'level 28' as the break keyword stops the switch before that point. If none of the cases match then the commands for the default will process.

 The default part of a switch is optional. If the default part is missing then the last case does not need a break keyword as this is the end of the switch now.

Some special control flow for objects include for...in to sequence through each object property. Providing a variable to store each property for the current iteration (or revolution) such as i or prop and the actual object name:

var props;
for (i in myProduct1) {
  props += i + ": " + myProduct1[i] + ", ";
}
Figure 28: Looping through objects with for...in

Error Handling

Object orientated languages have special kinds of errors that could be produced in a program or script such as the wrong type of data was submitted to a function, no data was submitted or some other condition that the script was not able to deal with. These types of errors are called exceptions.

If you need a part of the script to specifically generate an exception because the function requires a specific data type or requires only a specific range of values for instance; then you can generate an exception using the throw keyword and a string or number, variable or even an object.

var value;
if (input<10) {
  value = input;
} else {
  throw "invalidRangeException";
}
Figure 29: Throwing an exception

Exceptional error handling or exception handling can be done using the try...catch...finally statements. The try part contains the commands that might get errors. To provide the response of the exceptions you use the catch part. And in the optional finally part are any commands or statements that can be processed regardless of the outcome of the commands in the try part.

var value, response;
try {
  if (input<10) {
    value = input;
    response = value;
  } else {
    throw "invalidRangeException";
  }
} catch (e) {
  response = "Please provide a number below 10.";
}
Figure 30: A try...catch example

var value, response;
try {
  if (input<10) {
    value = input;
    response = value;
  } else {
    throw "invalidRangeException";
  }
} catch (e) {
  response = "Please provide a number below 10.";
} finally {
  response += " Enter a new value?";
}
Figure 31: A try...catch...finally example

If there is more than one exception that could occur then you may use more than one catch part, each catching a particular exception. Optionally you can also have a catch to catch any exceptions that do not match the others (like the default part of a switch):

var value, response;
try {
  if (input<2) {
    throw "valueIsTooLowException";
  } else if (input>8) {
    throw "valueIsTooHighException";
  } else {
    value = input;
    response = value;
  }
} catch (e if e == "valueIsTooLowException") {
  response = "Input is too low, please enter a number above 1.";
} catch (e if e == "valueIsTooHighException";) {
  response = "Input is too high, please enter a number below 9.";
} finally {
  response += " Enter a new value?";
}
Figure 32: A multiple catches example
var value, response;
try {
  if (input<2) {
    throw "valueIsTooLowException";
  } else if (input>8) {
    throw "valueIsTooHighException";
  } else {
    value = input;
    response = value;
  }
} catch (e if e == "valueIsTooLowException") {
  response = "Input is too low, please enter a number above 1.";
} catch (e if e == "valueIsTooHighException";) {
  response = "Input is too high, please enter a number below 9.";
} catch (e) {
  response = "An unknown error occurred";
} finally {
  response += " Enter a new value?";
}
Figure 33: A multiple catches with catch-all example

Unfortunately only Mozilla based UserAgents like Mozilla FireFox, SeaMonkey, Camino web browsers, ActiveState's Komodo IDE and Komodo Edit Code Editors, etc, support multiple catches. It seems it is too difficult to implement in Apple's WebKit, Opera's Presto, KDE's KTHML and no surprise Microsoft's Trident.

Regular Expressions

You can do advanced matches of data or parts of data using regular expressions (or regexp). A regular expression literal is surrounded by forward slashes:

var reg1 = /zyx/;
Figure 34: A basic regular expression literal

This assigns a match for any instance of 'zyx' in the string or variable that you would later perform a search on.

Alternatively you can use the RegExp object:

var reg1 = new RegExp("zyx");
Figure 35: A basic regular expression object

If you know the particular regular expression will not change then it is better to use the literal version as this will be compiled and the compiled version will be used at any time the regular expression is referred to.

A collection of special characters are usually used within regular expressions:

Starts with (circumflex ^)
Indicates the search phrase to the right is the beginning of the text.
Ends with (dollar sign $)
Indicates the search phrase to the left is the end of the text.
Any Single Character (dot .)
Indicates any one character that is not a dot.
Or (Vertical Bar |)
Provides 'this or this' ability.
A character group (opens with a square bracket and closes with an end square bracket [ ])
Allows you to provide a collection of characters to be the possible character or characters such as [a-zA-Z0-9] is a single letter or digit.
A negative character group (opens with a square bracket and circumflex and closes with an end square bracket [^ ])
Allows you to provide a collection of characters that will not be the character or characters such as [^7b@] is a single character that is not a number 7 or a letter b or an at sign.
Zero or more times (asterisk or star *)
Indicates that the character or group to the left occurs zero or more times.
One or more times (plus sign +)
Indicates that the character or group to the left occurs one or more times.
Zero or one (question mark ?)
Indicates that the character or group to the left occurs zero times or once.
A specific number of times (number within braces {8})
Indicates that the character or group to the left occurs that many times.
A least a specific number of times (number and comma within braces {8,})
Indicates that the character or group to the left occurs at least that many times.
A range (number and comma and number within braces {8,16})
Indicates that the character or group to the left occurs between the first number of times and the second number of times such as between 8 and 16 times.
A Number (backslash and lowercase letter d \d)
Indicates a number digit, 0 to 9.
Not a number (backslash and uppercase letter d \D)
Indicates it is anything but a digit.
A word (backslash and lowercase w \w)
Indicates a word.
Not a word (backslash and uppercase w \W)
Indicates it is anything but a word.
A whitespace (backslash and lowercase s \s)
Indicates a whitespace which is a space, a newline, a tab, etc.
Not a whitespace (backslash and uppercase s \S)
Indicates it is anything but a whitespace.

For instance, to find 'zyx' in the string "This is the zyxarmophic character with properties of the alterzyx effect." you use the exec() RegExp method or the match() String method.

var re = /zyx/;
var inhere = re.exec("This is the zyxarmophic character with properties of the alterzyx effect.");

var txt = new String("This is the zyxarmophic character with properties of the alterzyx effect.");
txt.match("/zyx/");
Figure 36: regexp

Or to simply see if 'hat' is in the string "The house sat on me hat" you can use the test() RegExp method or the search() String method.

var re = /hat/;
var inhere = re.test("The house sat on me hat");

var txt = new String("The house sat on me hat";
txt.search("/hat/");
Figure 37: regexp test

It would return true.

Instead of a string as the parameter of String's split() method you can use a regular expression.

Testing if 'Snow' is at the beginning of a string you use the circumflex character ( ^):

var re = /^Snow/;
var here = re.test("Snow Leopard has excellent accessibilities.");
Figure 38: Testing if a word is at the start

Testing if 'abilities.' is at the end of a string you use the dollar character ( $ ):

var re = /abilities\.$/;
var here = re.test("Snow Leopard has excellent accessibilities.$");
Figure 39: Testing if a word and a full stop is at the end

As a dot counts as a special character in regexp as a any single character except a full stop, we need to escape the dot using the backslash – making the dot non-special.

Testing if the string is exactly the text "Snow Leopard has excellent accessibilities." you use both the circumflex and dollar characters:

var re = /^Snow Leopard has excellent accessibilities\.$/;
var here = re.test("Snow Leopard has excellent accessibilities.");
Figure 40: Testing if a string has the exact text

More examples:

// Testing the letter a, one or more c's followed by an e exists
var re = /ac+e/;
var here = re.test("Snow Leopard has excellent accessibilities.");

// If there is zero or more words
var re = /\w*/;
var here = re.test("Snow Leopard has excellent accessibilities.");

// If there is at least 2 c's or at least 2 s's
var re = /c{2,}|s{2,}/;
var here = re.test("Snow Leopard has excellent accessibilities.");

// If there is one or more numbers
var re = /\d+/;
var here = re.test("Calculating the 33rd angle of the 48th m1038i");

// If there is at least one number followed by 2 letters that are only the letters s, t, h, r, d and /or n
var re = /\d+[sthrdn]{2}/;
var here = re.test("Calculating the 33rd angle of the 48th m1038i");
Figure 41: More regexp examples

Wrapping parts of the regexp in parenthesis will make it remember the actual part of the string it matches which is useful when doing replaces with the String objects replace() method.

var txt = new String("This tin has changed colour");
var result = txt.replace(/(\s[a-zA-Z])i([a-zA-Z]\s)/, "$1i$2");
Figure 42: String regexp replace

The above example matches a space followed by a letter, (\s[a-zA-Z]), which results as ' t' and is the first parenthesis in the regexp so is saved in $1; followed by the letter i; followed by the second parenthesis matching a letter and a space, ([a-zA-Z]\s), matching '' and saved in $2. You can then use the backreferences ($1, $2, etc) in replace()'s second parameter. Essentially replacing ' tin ' as ' tan '.

There are a few Flags in regexp that modify the search perspective.

Global ( g )
Matches more than one instance in the string.
Case Insensitive ( i )
Performs a case insensitive search.
Multiple Line ( m )
Makes the circumflex not only match the very beginning of the entire string but every beginning of a line within a multiple line string (contains \n characters). Also makes the dollar sign not only match the very end of the entire string but every end of a line within a multiple line string.

You can also use more than one flag together.

var re = /ac+e/gi;
var here = re.test("Snow Leopard has excellent acCessibilities.");

var re = new RegExp("ac+e", "gi");
var here = re.test("Snow Leopard has excellent acCessibilities.");
Figure 43: Using regexp flags

Webpages

Outputting the answers of calculations, functions, conditions, variables and other features from the script into the main flow of a webpage can be done in a number of ways. The way a script interacts with the main flow of a webpage is by using the Document Object Model or DOM (more information about the DOM in the Modelling The Document Objects article).

 In the DOM, the markup of the webpage is a hierarchy of webpage element objects such as the window object and the document object.

 Key windowf methods include print() which triggers sending the contents of the webpage to a physical printer or to a software printer such as a PDF converter depending on the print dialog options the user choose at the time.

 The document object for HTML (HyperText Markup Language) and XHTML (eXtensible HyperText Markup Language) webpages is actually an HTMLDocument object. Properties of this object include title to get the document title, URL providing the URI of the webpage, body to provide the body element object (HTMLBodyElement) and documentElement which provides the top html element object (HTMLHTMLElement).

 Key document methods include getElementById() with the value of the id="" attribute as the parameter. It obtains the actual element object that has that id="" attribute value. getElementsByName() and getElementsByTagName() both get an array of element objects with the same name as the method parameter such as var paras = document.getElementsByName("p"); results in an array of paragraph element objects (HTMLParagraphElement objects). You can then select a particular child element object from this array (HTMLCollection object) with the index of the child element object (first child object is zero) via the item() method such as:

var parasColl = document.getElementsByName("p");
parasColl.item(0);
Figure 44: Get an HTMLElement via getElementsByName() and item()

or by the body element:

var docbody = document.body;
docbody.item(0);
Figure 45: Get an HTMLElement via body and item()

 Once you've obtained the particular HTMLElement object, one way to output a variable, function or whatever from the script is to use the innerHTML or outerHTML properties of the HTMLElement object. For instance assigning strings, numbers, variables to a paragraph object replaces the paragraph's contents with the string / number / variable.

var paraObj1 = parasColl.item(0);
paraObj1.innerHTML = "The fruit is a" + fruit[3];
Figure 46: Display using innerHTML.

For outerHTML, it replaces the element contents and the element itself with the assigned value.

paraObj1.outerHTML = "<ul><li>" + fruit[3] + "</li></ul>";
Figure 47: Display using outerHTML.

The last example replacing the entire paragraph with an HTML unordered list.

Or you can put the output in a DOM Text Node and add the Text Node to the HTMLElement such as:

var txtout1 = document.createTextNode("The fruit is" + fruit[3]);
paraObj1.appendChild(txtout);
Figure 48: Display using DOM Text Node

Also some HTMLElements have a value property such as adding text to the fourth <textarea></textarea> element:

var taColl = document.body.getElementsByTagName("textarea");
var textObj4 = taColl.item(3);
textObj4.value += " The height is " + product1.dimensions["height"];
Figure 49: Display using value

The document object also has a couple of old methods that only work in HTML documents (they would throw Document Well Formed Errors on XML Documents including native XHTML webpages): write() and writeln().

document.write("<p>This is an outdated way of adding this HTML code.</p>");
Figure 50: Old document.write.

The document.writeln() is the same as above but automatically adds a newline character on the end. Again these methods are only available for backwards compatibility.

, Page 2

Copyright ©2009 Legend Scrolls and Peter Davison. All rights reserved.