Blog-Archiv

Mittwoch, 29. Oktober 2014

A JS Starter Kit for Beginners

In case you are interested in JavaScript and HTML, but you do not know how to begin, here is a starter kit for absolute beginners.

JS is a programming language that is interpreted by browsers (no compiler needed). A web browser and a text editor is everything you need. You don't even need internet access.

First create an HTML (Hyper-Text-Markup-Language) document, because JS normally runs in the context of a web page.

HTML Starter

Here is a minimalistic HTML web page you can use as template, copy & paste this into your favorite text editor:

<!DOCTYPE html>
<html>
  <head>
    <title>This will be displayed in the browser title bar.</title>
  </head>
     
  <body>

    <div>
     Here is my web page!
    </div>

  </body>

</html>

If you are on a platform that does not use UTF-8 as encoding, you would either need a text editor that lets you save in UTF-8, or, the better variant, you declare the encoding of your platform in the HTML document (here it is a WINDOWS-compatible encoding for western countries):

  <head>
    <meta charset="ISO-8859-1">

Now save the HTML text into the file system, let's assume you save it to (WINDOWS)

  • C:\me\mypage.html

UNIX people might save it to /home/me/mypage.html.

Now go to your browser and enter following text in the address line on top, and then press ENTER:

file:///C:/me/mypage.html

UNIX people will use file:///home/me/mypage.html.

What your browser now does is

  1. choose a communication protocol named "file:", which connects it to your local hard-disk, and then
  2. read the file in the given path as if it was a web page, and that directory was a web server's directory.

That's it, you should see the content of the web page in your browser now: Here is my web page!

The web pages you normally see in your browser come from the internet and are not stored on your hard-disk (or just temporarily), and you load them using the "http:" protocol and not "file:".
To work with the "http:" protocol you would need to install and start a web server on your machine (Apache, Tomcat, ...), and then make your page available for that web server. For playing around with JS you do not need a running web server, the "file:" protocol will do it.

JS Starter

The initial purpose of JS was to manipulate a web page in a user's browser. So JS mostly runs in the context of an HTML page, although it also can be used as normal scripting language, without HTML, outside of a web browser. But this kind of usage is not recommendable, because JS is full of gotchas and traps, there are much better scripting languages around.

But! As it is the most interpreted language in this world (only few internet pages have no JS in them), we are going to put some of it now into the starter HTML page.

Extend your web page to be the following:

<!DOCTYPE html>
<html>
  <head>
    <title>This will be displayed in the browser title bar.</title>
  </head>
     
  <body>

    <div>
      Here is my web page!
      
      <input value="Click Me" type="button" onclick="trace('Button has been clicked ...');"></input>
      <input value="Clear Me" type="button" onclick="clearTrace();"></input>
    </div>

    <script type="text/javascript">
    </script>

  </body>

</html>

In this HTML page there are two push buttons, the first creates a log line, the second clears all log lines. You see this implemented in the onclick attributes of the input elements, which actually contain JS code. (What you don't yet see here is the implementation of the called functions trace and clearTrace).

Then there is a script element at the end of the page. Script elements are best at the end of the page, because then the document is fully loaded and ready, and maybe the JS code in the script expects that all the HTML document object model (DOM) nodes are already available for manipulation.

Here comes the JS source code of the functions called in the onclick callbacks. Copy & paste it somewhere between the opening and closing script tags.

      var trace = function(text)  {
        var logLine = document.createElement("pre");
        logLine.setAttribute("style", "border: thin solid black;");
        logLine.appendChild(document.createTextNode(text));
        
        var logParagraph = document.getElementById("log");
        if ( ! logParagraph )  {
          logParagraph = document.createElement("p");
          logParagraph.setAttribute("id", "log");
          document.body.appendChild(logParagraph);
        }
        logParagraph.appendChild(logLine);
        
        if (console && console.log)
          console.log(text);
      };
      
      var clearTrace = function()  {
        var logParagraph = document.getElementById("log");
        if (logParagraph)  {
          var len = logParagraph.childNodes.length;
          for (var i = len - 1; i >= 0; i--)
            logParagraph.removeChild(logParagraph.childNodes[i]);
        }
      };
      
      trace("Hello JS log world!");

Now save the content of the web page to disk and press the "Reload" button in your browser (F5, or Ctl-F5). You should see something like this (try it, it works!):

Here is my web page!

On every "Click Me" button click there will be a new log line appended to the page, created by JS. Clicking the "Clear Me" button will clear all generated log lines.

This JS example code represents an output mechanism, logging directly into the page, and trying to write to the browser's console, if it exists and has a log function. (Try F12 to open the browser console, you should see a log line any time you click the "Click Me" button.)

In the first line of trace(), a HTML element of type pre is generated for the log line. The log line is then inserted into that parent element as a text node. Then an element with id="log" is searched in the entire document. When not found, it is created and appended to the end of the document. Then the pre element with the log text is appended to that "log" parent element.
In the clearTrace() function, an element with id "log" is searched, and when found, all child elements are removed from it, thus all log lines will disappear.

This is pure JavaScript, without help of jQuery. But it should run on any browser. You can find documentation about possible JS objects (like window, document, ...) and their properties and functions, including information by which browsers they are supported, on my JS / HtmlUnit report page. There you can click any object, function or property, and you will be taken to the Mozilla documentation page of it.

JS in Files

Of course you want to store your JS code into an external file.
Assuming you would save the JS code into a file named "trace.js" that is in a directory "js" relative to the HTML page, following HTML would represent that:

    <script type="text/javascript" src="js/trace.js"></script>

Replace the previous script tag by this, and your JS file should be read by the browser.
Mind that the script tag MUST NOT be written like that:

<script .... />

It MUST be written like that, else it might not be loaded:

<script .... ></script>

Don't know why, but this is a very popular gotcha.
Here is a HTML line to load the latest version of jQuery. You can put this into the head element:

    <script src="http://code.jquery.com/jquery.min.js" type="text/javascript"></script>

Better learn jQuery than JavaScript :-)

You can find more help at W3 Schools.
jQuery has a nice tutorial.
For experimenting with JS, js-fiddle is nice.
And here is my private reference.




Freitag, 24. Oktober 2014

JS Modules

Encapsulation in object-oriented programming languages always was a much disputed topic:

  • Doesn't encapsulation prevent code re-usage?
  • Why is it necessary to hide functionality?
  • Wouldn't this be a wonderful world if everything was public?

From my point of view the answer is

No, it would be an unforgiving and unpredictable world, where the wing beat of a butterfly on one side could cause a hurricane on the other side.
It's all about complexity, and how to border it. Complexity is like the water of a river after ten days of rain - it sweeps away everything.

Imagine many small problem solutions, forming the solution of a bigger problem, which again is just one of many solutions for an even bigger problem. Now the solution for the top problem doesn't work any more, and you must find the error.
Imagine everything in the source code is public. The error could be everywhere, because the programmers could have called everything from everywhere. But when they have separated public from private methods, the possible hazards are significantly less.

So what you need to do as software developer is

  1. solve a problem
  2. put the solution into a capsule, leaving open just the necessary access points (hiding complexity increases usability)
  3. use it, together with other such capsules, to build the solution for a bigger problem
When looking for an error then, you will not be confronted with the full complexity of the system, you will search only along the public ways until you find the malfunctioning capsule, only there you have to go into private details.

Remember:
Hide as much complexity as possible,
don't confront the outside world with complex details.

When JavaScript programmers talk about modules, they mostly mean objects with properties and functions that have access to nested variables and functions, the latter not being accessible from outside.
But JS does not have access modifiers. How can we achieve encapsulation?

Encapsulation Archetype

When you want to write some JS code without polluting the global namespace with variables and functions, you can do the following:

(function() {
  console.log("I am executing!");
}());

This is called a self-executing function. This kind of suicide is caused by the terminating parentheses (:-).
The comprehensive parentheses around the whole function definition are needed to be syntactically correct. But it doesn't seem to matter if they are just around the function definition or around all code, the following also works:

(function() {
  console.log("I am also executing!");
})();

You can also parameterize this capsule:

(function(what) {
  console.log("I am "+what+"!");
}("doing whatever you want"));

This outputs:

I am doing whatever you want!

Whatever you write inside the self-executing function will not "pollute" the global namespace. And it will be executed as soon as the JS interpreter encounters the terminating parentheses. So this represents an encapsulation archetype.

Module Archetype

Lets go JS-extreme and try a private function and variable:

var printer = (function() {
  var defaultWhat = "Default Hello World";
  
  function print(what)  {
    console.log(what || defaultWhat);
  }
  
  return {
    print: print
  };
})();

printer.print();
printer.print("Hello World");

When called, this outputs:

Default Hello World
Hello World

This is called the "Revealing Module Pattern" , because it solves problems in a private hidden space, and finally exports some public access points in the returned object.

But wait, here again we "polluted" the global namespace with a variable printer, holding a singleton object. Can't we do better?

Namespace Archetype

We can hide all our upcoming variables into our own namespace. However, we always must reserve a name for our namespace when it needs to be globally available.

A JS-namespace is an object, possibly holding other namespace objects. This might lead to a hierarchy of namespaces, built using the following pattern:

var my = my || {};
my.module = my.module || {};
my.module.printer = my.module.printer || {
  print: function(what)  {
    console.log(what);
  }
};

my.module.printer.print("Hi there");

Basically this reads as

"let variable 'my' be either the already existing 'my', or a new object when not yet defined."
So the object is created only the first time the JS interpreter executes this line.
We also could have written this like the following (with an ugly amount of indentation):

var my = my || {
  module: {
    printer: {
      print: function(what)  {
        console.log(what);
      }
    }
  }
};

my.module.printer.print("Hi there");

But mind that this is not exactly the same. When my already existed at this point, the module and printer objects would not have been written into the namespace! So better do it in the way shown before.

We could now drop properties/functions in the my space, or in the my.module space. Mind that everything in an object is visible and mutable from outside (public). The namespace is not a capsule, it is just a convenience, using long dotted names instead of simple names that once could get ambiguous.

Namespaced Module Instances

How about a function that dynamically creates new printer instances which can have a private state?

var my = my || {};
my.module = my.module || {};

my.module.createPrinter = my.module.createPrinter || function(toPrint) {
  var running = false;
  
  var on = function()  {
    running = true;
    console.log("Ra ta ta .... ");
  };
  var off = function()  {
    console.log("... ta ta: "+toPrint);
    running = false;
  };
  var state = function()  {
    return running;
  };
    
  return {
    start: on,
    stop: off,
    isRunning: state
  };
};

There is a private state in any created printer, represented by the running variable, and by the toPrint parameter. The latter is captured by the function closure and thus is available inside the function like a variable.

Mind that you shouldn't implement any function in the return-object. Just return references to the private functions inside the module capsule.

Here is some test code for this printer factory function:

var myFirstPrinter = my.module.createPrinter("First Hello World!");
console.log("myFirstPrinter.isRunning(): "+myFirstPrinter.isRunning());
myFirstPrinter.start();
console.log("myFirstPrinter.isRunning(): "+myFirstPrinter.isRunning());

var mySecondPrinter = my.module.createPrinter("Second Hello World!");
console.log("mySecondPrinter.isRunning(): "+mySecondPrinter.isRunning());
mySecondPrinter.start();
console.log("mySecondPrinter.isRunning(): "+mySecondPrinter.isRunning());

myFirstPrinter.stop();
console.log("myFirstPrinter.isRunning(): "+myFirstPrinter.isRunning());
console.log("mySecondPrinter.isRunning(): "+mySecondPrinter.isRunning());

mySecondPrinter.stop();
console.log("myFirstPrinter.isRunning(): "+myFirstPrinter.isRunning());
console.log("mySecondPrinter.isRunning(): "+mySecondPrinter.isRunning());

This outputs:

myFirstPrinter.isRunning(): false
Ra ta ta .... 
myFirstPrinter.isRunning(): true
mySecondPrinter.isRunning(): false
Ra ta ta .... 
mySecondPrinter.isRunning(): true
... ta ta: First Hello World!
myFirstPrinter.isRunning(): false
mySecondPrinter.isRunning(): true
... ta ta: Second Hello World!
myFirstPrinter.isRunning(): false
mySecondPrinter.isRunning(): false

As we see each printer has its own private state, not intervening with the states of other printer instances.

Module Instantiation with Inheritance

We can create module singletons, we can instantiate modules, now we want to instantiate modules that inherit from other modules!

I strongly advice to use functional inheritance, it is simple and transparent.
What we always need for functional inheritance is a function that can copy a super-object, to let reuse the functionality implemented there. Here is a simple utility to do that:

var shallowCopy = function(source) {
  if (source instanceof Function || ! (source instanceof Object))
    throw "shallowCopy() expected Object but got "+source;
 
  var target = {};
  var propertyName;
 
  for (propertyName in source)
    if (source.hasOwnProperty(propertyName))
      target[propertyName] = source[propertyName];
 
  return target;
}

When you have jQuery in your web page, you can use jQuery.extend() instead of this. jQuery is for browser engines what Java is for operating systems, so use it wherever you can.

We can derive the printer instance to be a suspendable printer:

my.module.createSuspendablePrinter = my.module.createSuspendablePrinter || function(toPrint) {
  var printer = my.module.createPrinter(toPrint); // define super-object
  var base = shallowCopy(printer); // save old implementations
  var suspended = false;
  
  printer.suspend = function()  {
    suspended = true;
    console.log("... suspending ...");
  };
  printer.resume = function()  {
    console.log("... resuming ...");
    suspended = false;
  };
  printer.isRunning = function()  { // override
    if (base.isRunning() && suspended) // call super
      return false;
    return base.isRunning();
  };
    
  return printer;
};

These test lines

var mySuspendablePrinter = my.module.createSuspendablePrinter("Hello Suspendable World!");
mySuspendablePrinter.start();
console.log("Started mySuspendablePrinter.isRunning(): "+mySuspendablePrinter.isRunning());
mySuspendablePrinter.suspend();
console.log("Suspended mySuspendablePrinter.isRunning(): "+mySuspendablePrinter.isRunning());
mySuspendablePrinter.resume();
console.log("Resumed mySuspendablePrinter.isRunning(): "+mySuspendablePrinter.isRunning());
mySuspendablePrinter.stop();
console.log("Stopped mySuspendablePrinter.isRunning(): "+mySuspendablePrinter.isRunning());

output the following

Ra ta ta .... 
Started mySuspendablePrinter.isRunning(): true
... suspending ...
Suspended mySuspendablePrinter.isRunning(): false
... resuming ...
Resumed mySuspendablePrinter.isRunning(): true
... ta ta: Hello Suspendable World!
Stopped mySuspendablePrinter.isRunning(): false

Hm, this printer is more a noise machine than something useful ... one more bad example :-(




Sonntag, 19. Oktober 2014

JS Functional Inheritance

We know that modern object-oriented programming languages provide inheritance to make life easier.
The lives of software developers that helplessly stray through jungles of inheritance hierarchies nobody found worth to document?
The lives of managers that can be sure that the maintenance of the software they sell will not make up 80% of the manufacturing costs, because it was written using OO techniques?

Inheritance lets us re-use existing, working and tested solutions, without any adapter code.
When using inheritance, we want to ...

  • benefit from the methods/fields of a super-class to solve new problems shortly and concise
  • overwrite methods the super-class implements, to change the class behaviour
  • call overwritten implementations from the sub-class, to re-use these defaults
  • implement an abstract super-class that solves problems in a general way, using abstract helper methods that have to be implemented then by concrete sub-classes
Generally spoken, inheritance is the best solution for the OnceAndOnlyOnce principle, which is one of the key criteria when it comes to the formidable software maintenance efforts.

So I want inheritance also in JavaScript. And I am confused about the many kinds of inheritance that seem to be available in JS, the most popular being

  • prototypal
  • pseudo-classical
  • functional
-> For me, one kind of inheritance that complies with criteria above would be enough!

The following is a kind of inheritance I developed during my JS studies. It is a slight extension of what is called "functional inheritance". It ...

  1. complies to all criteria listed above
  2. uses neither "this" nor "new" keywords
  3. and, surprise: functional inheritance allows private instance variables and functions!
I would call it "object-factory" inheritance.

Mind that it does not support the instanceof operator, I consider that being an anti-pattern.

Factory Functions

Base of this kind of inheritance are functions that create objects.
Here are basic factory functions for an "animal" inheritance tree:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
var animal = function(species)   {
  var object = {}; // define the class

  object.species = species;
  object.belly = "empty";
 
  object.eat = function(food) {
    object.belly = food;
  };
  object.toString = function() {
    return "species '"+object.species+
      "', belly("+object.belly+
      "), sounding "+object.sound(); // calling abstract function
  };
 
  return object;
};

var mammal = function(species, name)   {
  var object = animal(species); // define the super-class

  object.name = name; // adding a property

  object.giveBirth = function(babyName) {
    return object.create(babyName); // calling abstract function
  };

  var superToString = object.toString; // prepare super-calls

  object.toString = function() { // override with super call
    return "I am '"+object.name+"', "+superToString();
  };
 
  return object;
};

Every hierarchy level is represented by exactly one function that creates an object representing that inheritance level.

The base function animal() first creates a new empty object, because this is the base of the inheritance hierarchy. It populates that object with some general properties and functions all animals should have.
Mind that there is a call to a function called sound() that does NOT exist in the object returned from animal(). I would call this an "abstract function", to be implemented by sub-objects of animal.

The function mammal() then "extends" animal() by calling it, copying the returned animal, and then enriching it with properties and functions of a mammal.
Copying is optional, only needed if a mammal wants to use overwritten super-functions or -properties. Each inheritance level would see only its direct ancestor, but as all properties/functions of the super-object are copied into the more specialized object, the final sub-object would see all properties/functions of all levels, except the overwritten ones.

A mammal also uses an "abstract function" create(), and it overwrites toString() and calls super.toString(), which is named superToString here (super is a JS reserved word).

Objects from Factories

Here comes the usual cat and dog stuff.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var cat = function(name) {
  var object = mammal("Cat", name); // define the super-class

  object.create = cat; // define constructor

  object.sound = function() { // implementation of abstract function
    return "Meaou";
  };
 
  return object;
};

var dog = function(name) {
  var object = mammal("Dog", name); // define the super-class

  object.create = dog; // define constructor
 
  object.sound = function() { // implementation of abstract function
    return "Wouff Wouff";
  };

  return object;
};

These two sub-objects both must implement the "abstract functions", which is sound() and create() in this case.
Mind that I can reference the function dog() within its own function body for the create() function!

For both factories I could have dropped the shallowCopy() call, because neither needs a super-call.
Also a create() function is necessary only when a Cat instance must be able to create another Cat instance.

Here is some test code ...

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var garfield = cat("Garfield");
garfield.eat("catfish");
console.log(garfield.name+": "+garfield);

var catBaby = garfield.giveBirth("LittleGary");
console.log(garfield.name+"'s baby: "+catBaby);

var pluto = dog("Pluto");
pluto.eat("t-bone");
console.log(pluto.name+": "+pluto);

var dogBaby = pluto.giveBirth("LittleBloody");
console.log(pluto.name+"'s baby: "+dogBaby);

... and its output ...
Garfield: I am 'Garfield', species 'Cat', belly(catfish), sounding Meaou
Garfield's baby: I am 'LittleGary', species 'Cat', belly(empty), sounding Meaou
Pluto: I am 'Pluto', species 'Dog', belly(t-bone), sounding Wouff Wouff
Pluto's baby: I am 'LittleBloody', species 'Dog', belly(empty), sounding Wouff Wouff

Stepped into no gotcha, there are no bellies shared amongst these animals :-)

But, as I said before, the following prints false:

console.log("garfield instanceof cat: "+(garfield instanceof cat));

Reason is that there is no prototype used, and no new operator.
Here are some arguments against code using instanceof, which ...

  • speculates with the nature of classes, but that nature could change
  • is an excuse for not using correct sub-typing
  • implements things that should be implemented in the according class
Sorry for the term "class". We have no classes in JS, only objects. Although the factory functions above could be regarded as "class definitions".

Private Variables

Surprise: in functional inheritance private variables seem to work!
Try following example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var vehicle = function(type) {
  var that = {};
    
  that.type = type;

  return that;
}

var motorbike = function(whose) {
  var that = vehicle('motorbike');

  var numberOfWheels = 2;

  that.whose = whose;
    
  that.wheels = function () {
    console.log(that.whose+' '+that.type+' has '+numberOfWheels+' wheels');
  };
  that.increaseWheels = function () {
    numberOfWheels++;
    console.log("Increasing wheels on "+that.whose+' '+that.type+" to "+numberOfWheels);
  };

  return that;
};

The factory function motorbike() hosts a local variable storing the number of wheels of the vehicle. It has an initial value, and a public function can increment that value. And as we see, each motorbike instance has its own wheel counter!

Following test code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
var myMotorbike = motorbike("My");
myMotorbike.wheels(); 

var yourMotorbike = motorbike("Your");
yourMotorbike.wheels();

myMotorbike.increaseWheels();

myMotorbike.wheels();
yourMotorbike.wheels();

var hisMotorbike = motorbike("His");
hisMotorbike.wheels();

yourMotorbike.increaseWheels();
yourMotorbike.increaseWheels();

myMotorbike.wheels();
yourMotorbike.wheels();
hisMotorbike.wheels();

outputs this:

My motorbike has 2 wheels
Your motorbike has 2 wheels
Increasing wheels on My motorbike to 3
My motorbike has 3 wheels
Your motorbike has 2 wheels
His motorbike has 2 wheels
Increasing wheels on Your motorbike to 3
Increasing wheels on Your motorbike to 4
My motorbike has 3 wheels
Your motorbike has 4 wheels
His motorbike has 2 wheels

Lesson Learnt

To achieve module-encapsulation together with inheritance, JS functional inheritance provides all needed features.




Donnerstag, 16. Oktober 2014

JS Inheritance contra Encapsulation

Object-oriented languages have following features:

  • Data and functionality (that works on them) are grouped together in classes
  • A class is an abstraction of concrete objects that all have the same methods and properties (which can have different values)
  • Inheritance - a class can derive another class, and reuse and modify behaviour
  • Dynamic dispatch (overrides) - at runtime, the most specialized method in an inheritance hierarchy is executed
  • Method overloading - you can have methods foo() and foo(bar) and foo(bar1, bar2) ... in a class
  • Encapsulation - access modifiers like (at least) public and private
  • Open recursion - the "this" keyword that provides access to methods and properties of the same object

There are other less shortly explainable features, but lets sum up now for JavaScript.

  • Data and methods are grouped together: optionally yes, but functions are not bound to objects
  • A class as abstraction of concrete objects: no classes exist in JS
  • Inheritance: a frequently discussed topic, I would say "several kinds of, but no real"
  • Dynamic dispatch: yes, for prototypal inheritance
  • Method overloading - definitely not
  • Encapsulation - no, only local variables are some kind of "private"
  • Open recursion - "this" exists, but it points to the caller, not the owning object (although that's mostly the same, it's not always the same:-)

I would say, three of seven.

"Of course, JS is object-oriented , isn't everything in JS an object?"
"Yes", I answered, "and its functional too, everywhere you see functions ..."

The following is a result of my studies about JS inheritance, but it is nothing I can recommend, and you won't find a working inheritance solution here. You could skip this and read about functional inheritance, which is what I would advice.

Inheritance (pseudo-classical? prototypal?)

The only thing that is sure about JavaScript is that it is very flexible. So some kind of inheritance must be there, right?
If you search the web for JavaScript inheritance examples, you find things like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
var Animal = function(species) {
  this.species = species;
  this.food = "none";

  this.eat = function(givenFood) {
    this.food = givenFood;
  };
  this.toString = function() {
    return this.species+" ("+this.food+")";
  };
};

var Cat = function(name) {
  this.name = name;

  this.toString = function() {
    var superToString = Cat.prototype.toString.call(this); // super.toString()
    return this.name+" <"+superToString+">";
  };
};
Cat.prototype = new Animal("FourLegs");
Cat.prototype.constructor = Cat;

Animal and Cat are called constructor functions, and thus have capitalized names.
(You should never call such a function without the new operator, because such could cause unintended global variables.)

In Cat we have a super-object call which looks (and is) a little tedious:

Cat.prototype.toString.call(this);
Translated this reads as "take the overwritten function toString() from Cat's prototype object and execute it as if it was bound to 'this' Cat".

The line

Cat.prototype = new Animal("FourLegs");
is the "inheritance installation", meaning this is what you are supposed to do when you want an object to inherit from another (as there are no classes, you need objects that you can inherit from).

The line

Cat.prototype.constructor = Cat;
is for a proper constructor function, so that calling a Cat's constructor would create a Cat instance and not an Animal instance.

Here is some test code:

1
2
3
4
5
6
7
8
var garfield = new Cat("Garfield");
console.log("Garfield = "+garfield);
var catbert = new Cat("Catbert");
console.log("Catbert = "+catbert);
garfield.eat("mouse");
catbert.eat("cheese");
console.log("Garfield after meal = "+garfield);  // has he cheese?
console.log("Catbert after meal = "+catbert);

This code outputs:

Garfield = Garfield <FourLegs (none)>
Catbert = Catbert <FourLegs (none)>
Garfield after meal = Garfield <FourLegs (mouse)>
Catbert after meal = Catbert <FourLegs (cheese)>

What is in (parentheses) is what the cat has in its belly.
We need to make sure that Catbert has nothing in its belly that Garfield has eaten ;-)

Encapsulation

No problem until now, except that everything is public. Now I bring in what I would call a "private variable":

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
var Animal = function(species) {
  this.species = species;
 
  this.food = "none";
  var privFood = "empty"; // private
 
  this.eat = function(givenFood) {
    this.food = givenFood; // write to public field
    privFood = givenFood; // write to private field
  };
  this.toString = function() {
    return species+" ("+this.food+" / "+privFood+")";
  };
};

My expectation is that every instance of Cat has its own private privFood variable. The public food variable is for checking whether that assumption holds.
Running the same test lines as above, guess what's the result!

Garfield = Garfield <FourLegs (none / empty)>
Catbert = Catbert <FourLegs (none / empty)>
Garfield after meal = Garfield <FourLegs (mouse / cheese)>
Catbert after meal = Catbert <FourLegs (cheese / cheese)>

How can Garfield have "cheese" as its privFood variable?
When you consider that Garfield first eats a mouse, than Catbert eats "cheese", and Garfield then has "cheese" in its belly - this can not be a very private belly :-)

Isn't this a nice gotcha?

The privFood variable comes from the Animal instance in the prototype of Cat that Garfield and Catbert have in common! Not even always putting a new Animal instance to the Cat prototype when creating a new Cat helps.
This is the moment when JS experts start to talk about the "prototype chain", and complex diagrams are drawn.
At some point the technical issues become so overwhelming that you forget about the nice web-page you wanted to implement; that point is trespassed here and now.

Lesson Learnt

  • When you want objects that inherit from other objects using prototype, encapsulation (private variables) is becoming an expert work. Thus mostly everything will be public and mutable, at any time and from anywhere.
Especially on the way to modules this is a quite frustrating experience.



Mittwoch, 1. Oktober 2014

Running JS Scripts from Java with HtmlUnit

When studying JavaScript, I got tired from always having to write an HTML page around my script, just to be able to experiment with the language features. Normally I did a lot of console.log() or alert() calls to trace the execution (in times when browser debuggers were not yet mature). But the console was invisible by default, or it could be deactivated in some browsers, or not even supported. So I wanted to see results directly on the HTML page, and I started to do logElement.innerHTML = "..." and things like this. But such code depends on the surrounding HTML and thus did not always run.

Finally I decided to create a

in Eclipse.
I downloaded the "JavaScript Development Tools" from the "Eclipse Web Tools Platform" to get syntax highlighting for my JS scripts.
Using Java 8, I then wrote a Java program that can execute a JS script in the JS engine of the Java runtime ("Nashorn"). Here is the Java source.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class JavaScriptRunner
{
 /**
  * Executes given JavaScripts, given either by URLs, file paths, or as scripts.
  * Allocates a new engine instance for this call.
  */
 public final void execute(String [] jsUrlsOrFilesOrScripts) throws Exception {
  final ScriptEngineManager engineManager = new ScriptEngineManager();
  final ScriptEngine engine = engineManager.getEngineByMimeType("text/javascript");
  createGlobalBindings(engine);
  
  for (String jsUrlOrFileOrScript : jsUrlsOrFilesOrScripts) {
   Reader reader;
   try {
    final URL url = new URL(jsUrlOrFileOrScript);
    reader = new InputStreamReader(url.openStream());
   }
   catch (MalformedURLException e1) {
    try {
     reader = new FileReader(jsUrlOrFileOrScript);
    }
    catch (FileNotFoundException e2) {
     reader = new StringReader(jsUrlOrFileOrScript);
    }
   }
   
   engine.eval(new BufferedReader(reader));
  }
  
  cleanUp();
 }

 /**
  * Does nothing. Override this to create bindings for a BOM environment.
  */
 protected void addGlobalBindings(Bindings bindings) {
 }

 /**
  * Does nothing. Override this to clean up after JavaScript execution.
  */
 protected void cleanUp() {
 }

 private void createGlobalBindings(ScriptEngine engine) {
  final Bindings bindings = engine.createBindings();
  addGlobalBindings(bindings);
  engine.setBindings(bindings, ScriptContext.GLOBAL_SCOPE);
 }

}

As you can see I test the JS input to be an URL, when this fails I try to load it as file, when this fails it must be the script text itself.

The problem here is that the JavaScript statement console.log() does not work. Oracle recommends to use print() instead. But this wouldn't work in a browser page.

Note: Oracle added a new console application to the JDK that can run JS scripts. It is called jjs. It prompts for input when called without arguments. It provides print() instead of console.log().

So it was necessary to imitate the web-browser a little bit in Java. Reading the internet about the JS engine in Java 8 I then found out how I could provide a JS execution environment from Java.
I wrote following class and installed it into the JS execution context (called Bindings).

1
2
3
4
5
6
7
public class ConsoleMock
{
 public void log(Object text) {
  System.err.println(text);
 }

}

To be installed with following override:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class JavaScriptRunnerWithBomMocks extends JavaScriptRunner
{
 public static void main(String [] args) throws Exception {
  new JavaScriptRunnerWithBomMocks().execute(args);
 }

 /**
  * Creates naive BOM mock bindings.
  */
 protected void addGlobalBindings(Bindings bindings) {
  bindings.put("console", new ConsoleMock());
 }

}

Now I could load my first JS script and execute it.

1
2
3
4
5
function foo() {
  console.log("Hello World");
}

foo();

This worked.
JS was executing, Java was printing "Hello World" to stderr.
Basically, if you do something like window.alert("Hello Browser") in JS, you need to provide a Java class that has a public method alert(String message), and store an instance of this class into the JS engine's execution context under the name "window". That's all. You can then pop up a JDialog in the alert() implementation if you like :-)

Finally there was a script that worked a lot with the DOM (document object model) of the HTML page. I would have liked to let it run in that mock environment, just to see if there were major bugs in it.
I thought I could write further mock implementations like ConsoleMock, and imitate the w3c DOM API by delegating to its Java implementation. But this was a big disappointment, because I found out that browsers support only small parts of that API. My scripts wanted to call getElementsByClassName(), but this is not in the w3c API!

I ended up implementing the so-called BOM (browser object model), that consists of

  • window (the main object)
  • navigator (browser interface)
  • screen (device interface)
  • location (URL address interface)
  • history (back and forward buttons, reload)
  • document (including element, attribute, ...)
  • console
I installed these mock instances into the script engine like I did for the console. Result was a JavaScript environment that could edit an XML document, but not an HTML page.

Not a realistic test ground for my scripts!


The most interesting part in that work was the interaction between Java and JS. As the ConsoleMock (see above) was an example for a call from JS to Java, here is an example for a call from Java to JS. Subject is the JS window.setTimeout(callbackFunction, millis) call.
Here is the JS part:

1
2
3
4
5
function testFunction() {
 console.log("I am a callback function to be passed ");
}

window.setTimeout(testFunction, 1000);

And here is the Java side.
This implementation immediately calls the JS function, in a real world there would be a real timeout before that call.

1
2
3
4
5
6
7
8
public class WindowMock
{
 public int setTimeout(Runnable function, int millis) {
  function.run();
  return 0;
 }

}

To be installed with

1
2
3
 protected void addGlobalBindings(Bindings bindings) {
  bindings.put("window", new WindowMock());
 }

JS seems to look at the Java types in method setTimeout() and create adequate parameter objects to pass to the Java side. In this case it finds the Runnable interface and provides a JS object with a run() function, which then can be called by the Java side.


To be able to run my scripts also with an HTML object model, I tried to find some Java implementation that could provide all JavaScript functions and objects needed. I found HtmlUnit (called "headless browser") and tried to integrate it into my Eclipse test project. For that purpose I simply added the JAR files to a local lib directory, and from there to the Eclipse build-path.
Following JARs were sufficient:

 commons-codec-1.9.jar
 commons-collections-3.2.1.jar
 commons-io-2.4.jar
 commons-lang3-3.3.2.jar
 commons-logging-1.1.3.jar
 cssparser-0.9.14.jar
 htmlunit-2.15.jar
 htmlunit-core-js-2.15.jar
 httpclient-4.3.3.jar
 httpcore-4.3.2.jar
 httpmime-4.3.3.jar
 nekohtml-1.9.21.jar
 sac-1.3.jar
 serializer-2.7.1.jar
 xalan-2.7.1.jar
 xercesImpl-2.11.0.jar
 xml-apis-1.4.01.jar

The integration into the JS engine then looked like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public class JavaScriptRunnerWithHtmlUnit extends JavaScriptRunner
{
 public static void main(String [] args) throws Exception {
  final List<String> javaScripts = new ArrayList<String>();
  final List<String> webPages = new ArrayList<String>();
  for (String arg : args) {
   final String argument = arg.toLowerCase();
   if (argument.endsWith(".js"))
    javaScripts.add(arg);
   else if (argument.endsWith(".html") || argument.endsWith(".htm"))
    webPages.add(arg);
   else
    throw new IllegalArgumentException("Unknown extension: "+arg);
  }
  
  if (javaScripts.size() <= 0)
   throw new IllegalStateException("Having no JavaScripts to execute!");
  
  if (webPages.size() <= 0)
   webPages.add("http://www.this-page-intentionally-left-blank.org");
  
  for (String webPage : webPages)
   new JavaScriptRunnerWithHtmlUnit(webPage).execute(javaScripts.toArray(new String[javaScripts.size()]));
 }
 

 private final WebClient webClient;
 private final HtmlPage page;
 
 public JavaScriptRunnerWithHtmlUnit(String webPage) {
  this.webClient = new WebClient(/*BrowserVersion.IE8*/);
  try {
   page = webClient.getPage(webPage);
  }
  catch (FailingHttpStatusCodeException | IOException e) {
   throw new RuntimeException(e);
  }
  System.err.println("==========================================");
  System.err.println("Interpreting web page: "+webPage);
 }
 
 /**
  * Creates HtmlUnit BOM bindings.
  */
 protected void addGlobalBindings(Bindings bindings) {
  assert page != null;
  
  final Window window = (Window) page.getEnclosingWindow().getScriptObject();
  bindings.put("window", window);
  bindings.put("console", new ConsoleMock()); // window.getConsole() has not log(String) method
  bindings.put("document", window.getDocument());
  bindings.put("navigator", window.getNavigator());
  bindings.put("location", window.getLocation());
  bindings.put("history", window.getHistory());
  bindings.put("screen", window.getScreen());
 }
 
 @Override
 protected void cleanUp() {
  webClient.closeAllWindows();
 }

}

Voila! My JS scripts ran with any HTML page I gave them!
The tricky part was (Window) page.getEnclosingWindow().getScriptObject(), it took me some time to crawl through the HtmlUnit architecture an find this JS "window" proxy.

The problem with this environment is that you must pass all JS and HTML files on commandline. And the JS files must be in correct order. This is the consequence of a missing "import" statement in JS.

So far about my way to get a JS playground for experimenting and learning.


If you do not understand my Java classes, here is short take-away Java code to try out the Java 8 JS engine with HtmlUnit. Mind that you need the JARs listed above in your CLASSPATH.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
final ScriptEngineManager engineManager = new ScriptEngineManager();
final ScriptEngine engine = engineManager.getEngineByMimeType("text/javascript");
final Bindings bindings = engine.createBindings();
final WebClient webClient = new WebClient();
final HtmlPage page = webClient.getPage("http://www.this-page-intentionally-left-blank.org/");
final Window window = (Window) page.getEnclosingWindow().getScriptObject();
bindings.put("window", window);
bindings.put("document", window.getDocument());
bindings.put("navigator", window.getNavigator());
bindings.put("location", window.getLocation());
bindings.put("history", window.getHistory());
bindings.put("screen", window.getScreen());
engine.setBindings(bindings, ScriptContext.GLOBAL_SCOPE);
final URL url = new URL("http://code.jquery.com/jquery.js");
final Reader reader = new InputStreamReader(url.openStream());
engine.eval(new BufferedReader(reader));

One drawback of this environment is that I can not debug my scripts in it.

Another one is that I could not load jQuery.js.
It turned out that the Java JS engine (Nashorn) doesn't work together with HtmlUnit properly, because HtmlUnit is built on a Rhino fork (an older JS engine) and communicates via the Rhino Scriptable interface with JavaScript. For example, the JS function Array.slice() copies a given array when called without further arguments, but with the HtmlUnit nodes some unreported error seems to happen in Nashorn, resulting in an undefined return, which then makes jQuery fail.

Loading jQuery.js with the HtmlUnit Rhino fork and HtmlUnit as BOM provider finally worked:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
final WebClient webClient = new WebClient();
final HtmlPage page = webClient.getPage("http://www.this-page-intentionally-left-blank.org/");
final Window window = (Window) page.getEnclosingWindow().getScriptObject();
final Context context = Context.enter();
final Scriptable scope = context.initStandardObjects(window);
ScriptableObject.putProperty(scope, "console", Context.javaToJS(new ConsoleMock(), scope));
final URL url = new URL("http://code.jquery.com/jquery.js");
final Reader reader = new InputStreamReader(url.openStream());
context.evaluateReader(scope, reader, url.toString(), 1, null);
Context.exit();

But for some reason, the same failed when I used the HtmlUnit JS facility:

1
2
3
4
5
final WebClient webClient = new WebClient();
final HtmlPage page = webClient.getPage("http://www.this-page-intentionally-left-blank.org/");
final String source = "http://code.jquery.com/jquery.js";
final String scriptText = ....;  // read from source URL
webClient.getJavaScriptEngine().execute(page, scriptText, source, 1);


See also HtmlUnit JavaScript API support test statistics.

You can download Java sources for launching JS from Java here.



Glossary :-)

BOM: Web-browser object model, JS global variables like window, navigator, location, ...
BOM: Byte order mark, optional leading file bytes describing the encoding of the file
POM: Maven (Java build tool) project object model
POMMES: Fried potatoes