SlightlyLoony
Tera Contributor

find_real_file.pngYou may never need to temporarily extend a JavaScript class, but today I'm going to show you how to do it anyway. Why? Mainly because it's a useful introduction into two important concepts: JavaScript contexts, and the actual mechanics of JavaScript class extension.

The brown-eyed lass at right doesn't seem to be convinced any of this is useful. Let's see why it is...

The starting point today is GRUtil as I introduced it in the first post of this series: with a getTables() method, but without a getChildTables() method. Then we're going to run this code:

GRUtil.prototype.getChildTables = function(table) {
var om = Packages.com.glide.db.DBObjectManager.get();
var tables = om.getTableExtensions(table);
return j2js(tables);
};

var gru = new GRUtil();
gs.log(gru.getChildTables('cmdb_ci_server'));


What have we done here? If you dissect the first line of code, you see that we're assigning a function to the getChildTables property of the prototype property of the GRUtil object. Why on earth would we do such a crazy-looking thing? To understand why, you need to understand a little bit about how classes and objects work in JavaScript...

When JavaScript executes a piece of code like var x = new GRUtil(), here's what actually happens:
  1. A new object is created: an ordinary, untyped JavaScript object is created, exactly as if the code var x = {} had been executed.
  2. The new object is initialized: the properties of GRUtil.prototype are copied into the new object. In this case there are two such properties: initialize and getTables (which were put here by the GRUtil.prototype = {...} code in the GRUtil script include — plus the property getChildTables we added in the first line of code above. All of these properties happen to contain functions, but they could have been anything at all. When the copy has been completed, the new object has the same three properties.
  3. The new object's constructor function is called: because we've used the prototype.js library to construct our object, the visible effect is that the initialize method is called. Our object's initialize method is empty, so this does nothing. We'll be talking much more about this in later posts.


Creating a JavaScript objects makes a lot of work for the little nanognomes that run your computer!

Ok, that explains how that first line of code above could add the getChildTables method to GRUtil. But what was I babbling about when I mentioned JavaScript contexts?

JavaScript contexts are the environment that any particular JavaScript program executes in. Within the Service-now platform, the lifetime of a JavaScript context is generally either one web server request or one scheduled job. For most kinds of scripts that you might write, the former is the important one to understand. Each request is initiated by some action on the web browser. It could be that the user clicked on a button or link to go to a new page, and getting that new page would be one request. It could also be an AJAX request from JavaScript on a web page asking the Service-now instance for something; that would also be one request. For the duration of the work that the Service-now instance does to process that request, there is a single JavaScript context.

In the code above, we added a new property (getChildTables) to GRUtil.prototype. That modification occurs in memory, in the running program — not in the script include. The lifetime of the in-memory modified version is the same as the lifetime of the JavaScript context. When a new JavaScript context starts up, and GRUtil is referenced, then it is reloaded from the script include — and the modification our code above made would be missing (unless, of course, we re-ran that modifying code in the new JavaScript context).

So...do you think our brown-eyed lass is no longer puzzled? Or is she now wondering why she ever got interested in programming in the first place?