JavaScript Inheritance

This tutorial discusses JavaScript inheritance. However, since JavaScript is a class free programming language, the mechanism used is prototypal, rather than classical.
For this tutorial, I want to add functions to the String object. In JavaScript, the String object is pretty lean, if you're an experienced programmer, you'll be surprised to find that it doesn't have trim(), startsWith() or endsWith().
If you check out the documentation for Microsoft JScript, or Mozilla JavaScript, for the information on the JScript or JavaScript String object, you'll see what I mean.
Fortunately, in JavaScript we can add functions to any object using the prototype property of the object. This is, in essence, prototypal inheritance, and personally, it is one of the features of JavaScript which makes it so enjoyable.
Now, although I've scrupulously read the documentation, it may be that the functions I want to add (trim(), startsWith() and endsWith()) already exist. This could be because the documentation is wrong, or that this code is running in a newer JavaScript interpreter which has added these functions.
In the previous tutorial I explained a function called exists(), which can check if a specific property of specified type exists. So all I need to do is wrap my function definition in a test – if the function already exists, then I'll use that, otherwise I'll add my function:
if (!syger.exists(String.prototype, "newFunctionName”)) {
  String.prototype.newFunctionName = function () {
    // ...
  };
}

The Extensions Code

Let's now look at the code. First trim:
/**
 Trims leading and trailing whitespace from a string.
 From Douglas Crockford "Remedial JavaScript",
 http://javascript.crockford.com/remedial.html

 @returns the trimmed string.
*/

String.prototype.trim = function () {
  return this.replace(/^\s+|\s+$/g, "");
}; 
The next function is startsWith:
/**
 Checks if the string starts with the specified sub string.

 @param str the sub string to check for.
 @returns true if the string starts with the sub string, otherwise
  false.
*/

String.prototype.startsWith = function (str) {
  return this.indexOf(str) === 0;
};
Finally, we have the endsWith function:
/**
 Checks if the string ends with the specified sub string.

 @param str the sub string to check for.
 @returns true if the string ends with the sub string, otherwise
  false.
*/

String.prototype.endsWith = function (str) {
  var offset = this.length – str.length;
  return offset >= 0 && this.lastIndexOf(str) === offset;
};
There really isn't anything new here, except perhaps for the use of the this keyword, and regular expression syntax, both seen in the trim() function:
  return this.replace(/^\s+|\s+$/g, "");
When used inside a function the this keyword refers to the current object, which is the String object in the example above. Here it is calling the method replace which belongs to the String object.
Regular expressions can be defined within two slash characters (/), the following g specifies that the expression is global to the entire string. This particular regular expression reads: one or more whitespace characters at the start of the string, one or more whitespace characters at the end of the string. The replace method will substitute each match with the empty string "".

Using the Code

Now we can execute the example test code, provided in the Scripts/ExtensionsExample.js file, which is shown below:
// Create a short cut to the normal output device
if (!syger.exists(this, "puts")) {
  var puts = function (str) {
    document.write(str);
  };
}

obj = new String(" string object ");
puts(syger.introspect("string_object", obj) + "\n\n");

obj = " string object ";
puts("obj returns '" + obj + "'\n\n");

puts("trim() returns '" + obj.trim() + "'\n\n");

puts("startsWith(' str') returns " + obj.startsWith(' str') + "\n");
puts("startsWith('str') returns " + obj.startsWith('str') + "\n");
puts("startsWith(' string object longer ') returns " +
  obj.startsWith(' string object longer ') + "\n\n");

puts("endsWith('ect ') returns " + obj.endsWith('ect ') + "\n");
puts("endsWith('ect') returns " + obj.endsWith('ect') + "\n");
puts("endsWith(' string object longer ') returns " +
  obj.endsWith(' string object longer ') + "\n\n");

obj = typeOf("string literal");
puts("obj returns '" + obj + "'\n\n");
puts("startsWith('str') returns " + obj.startsWith('str') + "\n");
puts("endsWith('ing') returns " + obj.endsWith('ing'));
You've already met the five lines of code at the start in the previous tutorial. The next two lines call the introspect method to see if the new functions have been added. The following two lines create a string and print it's value. Next the trim() method is tested, then the startsWith() method, and finally the endsWith() method.
The last four lines of the example use the new methods on a string which is returned by the typeof keyword (a built-in method). As you can see in the results below, even this string has the additional methods, even though it was produced by code which did not know of their existence.
Now we can run the example code, which gives the following results:

Note: if you don't see anything in monospaced type above this line, you probably have JavaScript disabled in your browser. This is a live demonstration, so you'll need to enable JavaScript!
The introspect method currently shows the three new methods. As I explained above, this could change in the future.
Next we see the value of our string, which has leading and trailing spaces (the example code adds the single quotes, by the way). Then we see the result of trimming the string.
The startsWith and endsWith tests use the original string, not the trimmed string. They also test for substrings which are actually longer than the string being tested.
Finally, the same methods are used on the string returned by the typeof keyword, which has the value "string".
The next tutorial explains closures.
All the scripts in these tutorials are available for download as two compressed archives; Scripts.zip and AspScripts.zip.

Contacts

Syger can be contacted for consultancy work on any of the topics mentioned in this article, by sending an email to info@syger.it.

Valid CSS

Valid XHTML 1.0

Valid Atom 1.0