JavasScript Language Overview

(Written for the Elte/PGY3 class)

Please inspect the source of the document to see JavaScript code, and explanations in comments! For a generic introduction to JavaScript, please see: https://developer.mozilla.org/en/About_JavaScript. Detailed JavaScript language documentation is available at https://developer.mozilla.org/en/JavaScript/Guide and https://developer.mozilla.org/en/JavaScript/Reference

1. Adding JavaScript to the HTML page

You use the <script> tag to add JavaScript code: definitions, function declaraions and statements

Code is either supplied inside the tag: e.g. <script type="text/javascript> var aaa = 10; </script>, or loaded from another URL, like <script type="text/javascript src="MyScript.js"/>

The type attribute is oficially mandatory, but modern browsers do not seem to require it

2. Writing the html document from JavaScript

From within the script tag, any HTML code can be generated using document.write()
"document" is the object that represents the HTML document.

E.g.:

     document.write("<i>Hej!!!  </i><br>");
     document.write('<b>Haj!!!  </b>');
This example also shows that string literals are delimited either by ' ' or by " " (the pairs must match!). This way you can use string literals in Javascript code specified within HTML tag attributes.

This is not the trickiest way of creating HTML from code, but may be useful, e.g. if the data you are using is not formatted in the proper HTML you need, and you do no want to reformat it on the server side. The real trick is rather to manipulate your document after it is loaded, i.e. through the DOM.

3. Objects in Javascript

In javascript, an object is pretty much a map of key-value pairs. Genarally you select values via the [ ] operator, e.g. rect["width"] Thanks to JavaScript's lenient data type model, you do not need classes to create useful objects: you can just create (using new) an instance of the internal class Object, and add any number of variables and methods using different keys. As long as you remember those keys, you can use the object.

Like in Java, objects are created using the new operator. It is useful to remember that for each existing object, a new was executed somewhere.

 

        var anyvar = new Object;    // create object from generic class

        anyvar.length = 10;

        anyvar.width = 20;

        anyvar["Funny varName"] = "Value for a strange key";

        anyvar.selfReference = anyvar;

        anyvar.describe = function(language) {
             switch(language) {
               case "HU" : tfirst = "Ez egy téglalap, területe: ";
                           tsecond = " kerülete: ";
                           break;
               case "DE" : tfirst = "Dass is ein Rechteck, Oberflache: ";
                           tsecond = " Umfassung: ";
                           break;
               default:
                           tfirst = "This is a rectangle, area: ";
                           tsecond = " perimeter: "
             }
             return tfirst + (this.length * this.width) + tsecond + (this.length * this.width);
        }

//        Now let us try this:

        document.write( "English: " +anyvar.describe("EN") + '<br>');
        document.write( "Deutsch: " + anyvar.selfReference.describe("HU") + '<br>');
        document.write(anyvar["Funny varName"]);

Obviously, the object can be used even from other Javascripts in your page:
        document.write( "Magyarul: " + anyvar.describe("HU"));

4. Objects in Javascript - from 'classes'

If you define a regular (named) function (with or without arguments, and/or a return value), you automatically have a 'class' from which you can instantiate new instances.

There is one extra, however: you can use the this keyword to access the object's member variables.

This is especially useful, because the method will also become the constructor of your class, i.e. you can initialize your new object from within the constructor.

(Actually, you can also invoke the function normally - i.e. without new -, in which case "this" will refer to the object of the context object of the browser window it is executing in.)

        function spaceship(mission_num) {
                this.codename = "Apollo" + mission_num;
                return mission_num + 1900;
        }

        MyObject = new spaceship(55);      // creation of new object (function's return value is lost)
        MyCodeInt = spaceship(13);         // simple assignment to a variable. As a side effect, it will
                                           // also assign a value to the 'codename' property of the current context object)

        document.write( "New object's name: " + MyObject.codename + "<br>");
        document.write( "Variable value: " + MyCodeInt + "<br>");

        document.write("'this' is an " + this + ", but it already has its codename property set to " + this.codename + "<br>");

        // object literal: this creates an istance of the built in Object class.
        var myObj = {
                 message: "Hello, ",
                codename= "Szojuz"
        }


This is not all about Javascript objects. You can also create complex inheritance schemes using the prototype context, which is not described here. You can find a good intro at https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Details_of_the_Object_Model#Class-Based_vs._Prototype-Based_Languages

5. Functions/methods in Javascript

The assignment of a method (see above, the "describe" object method in example 3), also demonstrates a nice language feature: funcion literals, i.e. functions that are not identified by name, rather they are immediately assigned (e.g. to a normal variable, or an object's field). I.e. in addition to normal, named functions, you can create functions "on the fly", and assign it to something or use it imemadiately. Function literals are specified by the 'function' keyword, immediately followed by the parameter list.
        MyFun = function(msg) {
                      document.write("Function call: " + msg);
        };
        MyFun("This is the message for the day");

Functions are like most modern languages, where local variables of the caller's context is not visible. However, functions defined within other functions can reach (i.e read/write) the local variables of the definition parent function.

A seen above, they can also be exported from their parent function (either by assignment to a variable or through a return value).

This can lead to interesting scenarios where the local variables of a function call continue to be available after the functions terminates.

        TestFun = function(arg1) {
                      var localvar = "Number" + arg1;
                      ff = function() {                // the child function accesses parent's localvars
                           document.write("Var of my parent: " + localvar);
                      }
                      return ff;
        };
        Fun1 = TestFun(99);
        Fun2 = TestFun(131);
        document.write("Let us see the invocation of Fun1 after the parent is gone: <br><i>");
        Fun1();
        document.write("</i><br>...and Fun2: <br><i>");
        Fun2();
        document.write("</i>");

Note that each invocation of the method creates a different context; This mechanism is called closure and is a typical feature of modern languages. For JavaScript, this even has a practical application, i.e the use of closures as callback methods. Callbacks typically need some information from the setup environment to execute properly.

In "C", this was regularly solved by an extra parameter (also named "param") passed along with the function when setting up the callback mechanism. The formal parameter list of the callback function was also extended for this extra param, which was thus passed back exactly as it was received. (This param typically contained a pointer to some data structure.)

Object oriented frameworks (C++, Java) typically require an object as callback, i.e. the callback is an interface whose method is called.

JavaScript does not support interfaces, but here setting up a callback is even more elagant: you can reference the environment (local variables and function arguments) of the definition parent without any extra effort.

Reload this page to restart timer and see closures in action!

        function SetupTimerBoxFor(boxid, username) {
            var TestFun = function() {
                // we are referencing the username argument of the definition parent
                document.getElementById(boxid).innerHTML = "Time is gone, " + username + " "; }

            setTimeout(TestFun, 3000);
        }

        // "Bumburnyák" is the local data used by the callback long after SetupTimerBox has returned
        SeturpTimerBoxFor("timebox", "Bumburnyák");

....  // a HTML segment follows:

<div style="background:#FFE0E0" id="timebox">Waiting for timer...>

Waiting for timer...

In addition to timers, JavaScript also uses callbacks to handle user input, and Network communication (XMLHttpRequest) events, so the function literal and closure mechanisms are quite common in advanced JavaScript code.

6. HTML Events and propagation

HTML Elements can receive events in JavaScript. Elements are processed both by the topmost element affected and also by all their parents. Parent element hadlers registered in 'Capture' mode receive events before their child, while 'Cascading' handlers are called after the childs handlers. Element events can be added to using special HTML attributes (e.g onClick, where a statement to be evalated is specified) or they can be explicitly added to the DOM using addEventListener(), where a function to be calld is specified.

 

    <form id = "f1" name="form1" onclick="handleEvent(this,'');">
      <button type="button" id="button1" name="ClickMe" title="Click Me!"
              onclick="handleEvent(this,'');">
        Click Me!
      </button>
    </form>
<script>
    function handleEvent(element, event) {
        alert("Event on " + element.getAttribute("name") + ": " +event)    
    }

    // now add handlers using DOM methods
    var theForm = document.getElementById("f1");
    // specify function using function literals. Parameter 3 controls 'Capture'/'Cascade' mode
    theForm.addEventListener('click',function() { alert("Gyerekek elott: " + this.getAttribute("name")); },true)
    theForm.addEventListener('click',function() { alert("Gyerekek utan: " + this.getAttribute("name")); },false)
</script>
    
## This is an enclosing <form> tag

## end of <form>

7. Communicate with the server: XMLHttpRequest example

JavaScript's abaility to access additional info from a server is provided by the XMLHttpRequest API. (For security reasons, only the 'source' server can be accessed, i.e. which provided the original html data being displayed.)

We start out from an empty XMLHttpRequest object, and specify the source (with .open(...)), and send the request via .send(...).

Depending on the third open parameter, downloading can be either synchronous or asynchronous.

In the synchronous case, send bocks until the requested resource is downloaded (or an error occurs). Trivially, downlaod status and data can be accessed through the request object.

The asynchronous mode is much more interesting, as it is demonstrated below. In this case, send() returns immediately (allowing the browser UI do any other task, e.g. response to user actions). The outcome of the download is communicated via the onreadystatechange() callback, which examines some status info to identify successful download, but it also accesses the verbatim text of the downloaded resource (responseText).

Please note, that this callback is again a closure, as it accesses the http_req object long after download_test has returned.

XMLHttpRequest is basically a facility to retrieve any text, but if the MIME-Type indicates an XML document (e.g. "application/xml"), the response can also be parsed as an XML file, and made available as a DOM tree when accessing the responseXML property of the request.

Another interesting point is that data can also be send by using "POST" or "PUT" with the open(), and providing non-null data with send(). The open() method also accepts username and password in the optional 4th and 5th parameters.

   function download_test() {
      http_req=new XMLHttpRequest();
      http_req.open("GET","/index.html",true);  // true requests asynchronous download
      http_req.onreadystatechange = function (aEvt) {  
          if (http_req.readyState == 4) {       // 4 means 'DONE' i.e. the final state
             if (http_req.status == 200)  
              alert("/index.html length is " + http_req.responseText.length + " chars");
          else  
             alert('Error', http_req.statusText);  
          }  
      };  
      http_req.send(null);  
    };