An Excursion to JavaScript


There's strictly no warranty for the correctness of this text. You use any of the information provided here at your own risk.


Contents:

  1. HTML-Basics
  2. About JavaScript
  3. Running JavaScript Code. Displaying Text. "Hello World".
  4. Comments
  5. Variables. Arrays
  6. for-Loops
  7. while, if. Functions.
  8. String-Functions
  9. Getting User-Input. Cookie-Monster Script
  10. Classes
  11. Buttons and Event Handlers
  12. Processing Mouse Activity
  13. Radiobuttons
  14. Drawing on a Canvas Widget
  15. Loading and Saving Text Files


1. HTML-Basics

Before we begin with JavaScript-programming, we probably need some basic knowledge of HTML.

HTML ("Hypertext Markup Language") is the text-format of webpages. Webbrowsers are usually pointed to files in ".html"-format, or receive such files from webservers. It is the main task of webbrowsers to read pages of HTML-code, and display them on the screen.

To add formatting information to plain text, HTML uses socalled "tags". They use this format:

<tag>Text</tag>

If the browser knows, that the tag is supposed to end at the end of the line, the last (closing) part can also be left out.
HTML-pages have a "head" with general information about the website. The website's text is inside a tag called "body". The whole website is inside a tag called "html":

<!DOCTYPE html>
<html>
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   <title>Test</title>
</head>
<body>
Hello
</body>
</html>
<!DOCTYPE html>
<html>
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   <title>First Document</title>
</head>
<body>
<h3>First Document</h3>
<p>Hello from <b>this</b> document.
<p>Let's see, what <i>else</i> we can do.
<br>Maybe just write a new line first.
<p>Let's have some &nbsp;&nbsp;<u>space</u>.
<p>A <a href="https://www.fsf.org">link to the Free Software Foundation</a>.
<p>Finally an enumeration:
<ol>
<li>One
<li>Two
<li>Three
</ol>
<hr>
</body>
</html>

Tags can have attributes: For example "<hr width=50%>" produces a line, that's horizontally just half the size of the webpage.
The "id"-attribute makes it possible for JavaScript-scripts to find a certain HTML-element in the website, for example a certain paragraph: "<p id="specialparagraph">".

JavaScript-scripts can be embedded into the website, by writing them between "<script> ... </script>".
They can be written inside the body- or the head-part of the website. Often, they are in the head-part.

If you want to learn more about HTML, you can follow this tutorial, or if you know German, the website "selfhtml" used to be a nice resource.


2. About JavaScript

JavaScript is the main scripting language interpreted by webbrowsers to be used in websites.

It was first created 1995 by Brendan Eich during the times of "Web 1.0", and was integrated into the Netscape Navigator. Since then, many changes have been made to the language, so that it has become quite usable (especially since a major update in 2015). It may happen, that modern JavaScript code doesn't run in rather old browsers, but it also seems, that most people use recent browsers.

JavaScript is a scripting language, and people can just run the code inside their browser. That still seems to be its main advantage.


3. Running JavaScript Code. Displaying Text. "Hello World".

First, let's get some output like "Hello World" from JavaScript. It's the programming language to run in a web-browser though, and just displaying some text in a web-page would be done in plain HTML instead. To use JavaScript, we could embed an according script into a HTML-page. This script could then write to the web-page dynamically:

<!DOCTYPE html>
<html>
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   <title>Test</title>
</head>
<body>
<script>
document.write("Hello World");
</script>
</body>
</html>

The output can be viewed by pointing a web-browser to a ".html"-file with this content.

The HTML-code and the JavaScript-code can also be separated into two different files: "hello.html":

<!DOCTYPE html>
<html>
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   <title>Test</title>
</head>
<body>
<script src="hello.js"></script>
</body>
</html>

And "hello.js" (just one line in this case):

document.write("Hello World");

The browser can then be kept pointing to "hello.html", while "hello.js" can be edited. To view the changes, just the "Reload"-button of the browser can be clicked. This is a useful procedure during development.

Besides "document.write(...);", which changes the current web-page,

console.log("Hello World");

can also be used to produce text output. It is then shown in the "console". "F12" has to be pressed in Firefox, and the tab "Console" has to be selected in the opening window, to see it.

Another way to display text is to use

window.alert("Hello World");

It shows the text in a popup-window of the browser.

Often, you want to want to write text to a certain position on the web-page. This is done, by using an ""id=...""-tag in an element inside the HTML-code, find that element using the "id" in JavaScript, and then replace the element's content:

<!DOCTYPE html>
<html>
<body>
<p>Print something from JavaScript:
<p id="myId">This text will be replaced.</p>
<script>
document.getElementById("myId").innerHTML = "Hello World";
</script>
</body>
</html>

There is also an interpreter called "Node.js" that directly runs "node hello.js" without a browser. But most of the time, you probably want to use JavaScript in a browser.


4. Comments

In JavaScript-code, C++- and C-style comments (Comment 1 and Comment 2) can be used, and also HTML-style comments (Comment 3):

// Comment 1

/*  Comment 2 */

<!-- Comment 3 -->

"#" isn't supported though.


5. Variables. Arrays

The keyword "var" was used for to declare variables up to 2015. Now it's considered obsolete. Today, the keyword "const" is used, if the variable isn't supposed to be changed, and "let", if the variable will be changed.
Variables can store numbers and strings, like scalar variables in Perl.

const a = 5;
const b = "Hello";
let c = 6;
c = 10;

To discard the decimal-part of a number (for example change 5.438 to 5), use the function "Math.trunc()" (like using "int()" in Perl).

There are the boolean values "true" and "false".
There's also "undefined". That's the value, variables get, when they are declared, but not yet initialized.
Furthermore, there's "null" and "NaN" (= "Not a Number"). "null" is not the same as NULL or Null. If a variable is "null" is checked with "if (a == null) {}.

There are also arrays. (The "const" refers to the reference to the array here, so elements of the array can still be changed though using "const"):

const fruits = ["apple", "banana"];
fruits[0] = "orange";
fruits.push("cherry");
document.write(fruits.length);
document.write(fruits.indexOf("banana"));

There are also objects. Their attributes can be initialized immediately, resulting in something like a hash or a dictionary:

const apple = {type: "Golden Delicious", color : "green", "price" : 1};
document.write(apple.type);

The operator "typeof" tells the datatype of a variable.


6. for-Loops

for-loops in C-style work:

let i;
for (i = 0; i < 10; i++) {
    document.write(i + " ");
}

There's also a way to iterate over an array (like "foreach()" in Perl):

const fruits = ["apple", "banana", "cherry"];
let i;
for (i of fruits) {
    document.write(i + " ");
}

And it's also possible to iterate over the attributes of an object, again similar to iterating over hashes or dictionaries:

const apple = {type: "Golden Delicious", color : "green", "price" : 1};
let key;
for (key in apple) {
    document.write(key + ": " + apple[key] + "<br>");
}

Unlike the keys of Python-dictionaries, which can be for example strings, the keys in the JavaScript-code here are real identifiers of object-attributes.


7. while, if. Functions.

while and if just work as expected:

let a = 1;
while (a < 5) {
    document.write(a + "<br>");
    a++;
}
if (a == 5) {
    document.write("a is 5.");
} else {
    document.write("a is not 5.");
}

For checking a variable against several alternative values, there's also switch/case, like in C.

There are functions as well. They use the keyword "function" (instead of "sub" (Perl) or "def" (Python)). When using methods inside classes, the keyword "function" is left out.


8. String-Functions


9. Getting User-Input. Cookie-Monster Script

I use to write this script in various languages. In JavaScript, getting user input is combined with HTML, for example with "form" and "input" elements:

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">

function processInput() {
    const cookies = document.getElementById('cookies').value;
    if (cookies != "COOKIES") {
        return;
    }
    window.alert("Mmmm. COOKIES.");
}
</script>
</head>

<body>
<h2>Cookie Monster</h2>
<form action="javascript:processInput()">
  <label for="cookies">I want COOKIES:</label><br>
  <input type="text" id="cookies" name="cookies"><br>
  <p>
  <input type="submit" value="Submit">
</form>
</body>
</html>

In contrast to the example-scripts above, the JavaScript-code is not executed immediately here.
The "<script>"-part is outside the HTML-body in the "<head>"-area.
The function "processInput()" is only called, when it is triggered by the HTML "form"-element, for example by pressing the "Submit" button. In the function "processInput()", the "input/text"-element is then found by the JavaScript-code by the "id"-tag, so that its value can be read.


10. Classes

Since 2015, JavaScript also has classes. Here's the "Lamp"-example, I usually write to demonstrate them:

class Lamp {

    constructor(name, lightintensity, state) {
        this.name = name;
        this.state = state;
        this.lightintensity = lightintensity;
    }

    switchOn() {
        this.state = "on";
        document.write("'" + this.name + "' is on at " + this.lightintensity + " Watt.");
        document.write("<br>");
    }

    switchOff() {
        this.state = "off";
        document.write("'" + this.name + "' is off.");
        document.write("<br>");
    }

    newLightBulb(light) {
        if (this.state == "on") {
            document.write("Light bulb can not be changed.");
            document.write("<br>");
            document.write("First, '" + this.name + "' has to be switched off.");
            document.write("<br>");
        } else {
            this.lightintensity = light;
            document.write("Light bulb in '" + this.name + "' has been changed.");
            document.write("<br>");
            document.write("The new bulb has " + this.lightintensity + " Watt.");
            document.write("<br>");
            this.switchOn();
        }
    }
}

const lamp1 = new Lamp("First Lamp", 50, "off");
const lamp2 = new Lamp("Second Lamp", 40, "off");
lamp1.switchOn();
lamp2.switchOn();
lamp2.newLightBulb(100);
lamp2.switchOff();
lamp2.newLightBulb(100);

The keyword "this" is used (like in C++) to represent the class inside itself (Python uses the keyword "self" instead). It's not necessary to pass "this" to methods as the first argument. That a method belongs to the class, is determined by the curly brackets around the class.
The keyword "function" isn't used, when declaring a method (unlike Python, where "def" is also used to declare a method).


11. Buttons and Event Handlers

To make a website element like a button react to user input, a socalled "event listener" has to be set up.

Window applications and also video games have a socalled "main loop". This loop is running all the time, while the application is running. Usually at about 60 frames (loops) per second. Inside this loop, everything the application does is determined. Because the loop runs so fast, it appears to the user, that the application does several things simultaneously, for example play a Youtube-video and check for his mouse-input at the "same" time. Although technically, the processor still just executes one instruction after the other.
With the method ".addEventListener()", a JavaScript-script can add something, to which the browser should listen in its main loop. The main loop then continues running, and now also checks for the events defined in the JavaScript-script. If such an event occurs, it then triggers the function, that is defined in the script.

So, in HTML/JavaScript, a button is set up for example like this:

<!DOCTYPE html>
<html>
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   <title>Test</title>
</head>
<body>
<p>
<div style="text-indent:100pt;">
<button type="button" id="mybutton">Click here</button>
<script>

function buttonPressed(argument) {
    console.log(argument);
    window.alert("Button pressed.");
}

document.getElementById("mybutton").addEventListener("click", function(event) { buttonPressed("Argument") });
</script>
</body>
</html>

An event handler is set up, that is connected to the button. The browser's main loop now also listens for the button to be clicked. When the event occurs, the function is called. It is an anonymous function here, so that arguments can be passed from the function-calls inside it.
It would also be possible to declare a function to be called directly, like this:

document.getElementById("mybutton").addEventListener("click", buttonPressed);

(without the round function-brackets then), but then, arguments couldn't be passed to the function. In this case, the called function has to have a parameter "event" to capture the event-object, that is passed to it automatically.

But we're using an anonymous function as shown above. It also automatically receives the argument "event" from the event-processing-process. The "event"-object holds attributes to get information about the event. (If the event was a keyboard-press for example, the "event"-object would hold the information, which key was pressed, so that object is sometimes of importance.)

Note: If this JavaScript-type event-handler is set up in a class like a "main"-class, the called function is not aware of the class, even if it is in the class. My work-around for that is, to define "main" in the script's main namespace and to also define the event-handlers there. "main" is then known in the anonymous function of the event-handler, and can be passed to functions from there. And as all classes depend on "main", the whole application is then known in the called functions. Example:

<!DOCTYPE html>
<html>
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<p>
<div style="text-indent:100pt;">
<button type="button" id="mybutton">Click here</button>
<script>

class MessagePrinter {
    constructor(message) {
        this.message = message;
    }

    printMessage() {
        window.alert(this.message);
    }
}

class Main {
    constructor() {
        this.mp = new MessagePrinter("Hello"); 
    }
    doSomething() {
        this.mp.printMessage();
    }
}

function buttonPressed(main) {
    // main and its subclasses are known here:
    main.doSomething();
}

main = new Main();

document.getElementById("mybutton").addEventListener("click", function(event) { buttonPressed(main); });
</script>
</body>
</html>


12. Processing Mouse Activity

As seen in the line:

document.getElementById("mybutton").addEventListener("click", function(event) { buttonPressed("Argument") });

event handlers can listen to "click". They can also listen to "mousedown", "mousemove" and "mouseup" to react to mouse activity.

This function tells, if the first mouse button is pressed at the moment:

getFirstMouseButtonPressed(event) {
    let flags = event.buttons !== undefined ? event.buttons : event.which;
    buttondown = (flags & 1) === 1;
    // Returns true or false:
    return buttondown;
}

If there's a canvas in the document, the mouse position inside the canvas can be found like this:

const canvas      = document.getElementById("canvas");
const context     = canvas.getContext("2d");
const canvasrect  = this.canvas.getBoundingClientRect();
let mouseposition = [event.clientX - main.canvasrect.left, event.clientY - main.canvasrect.top];


13. Radiobuttons

Radiobuttons are a way to get a choice of one value of several alternatives from the user in a GUI. They are implemented in HTML/JavaScript like this:

<!DOCTYPE html>
<html>
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   <title>Test</title>
</head>
<body>
<p>

<form name="selections">
<input type="radio" name="selection" id="rb_1" value="1"> Choice 1</input>
&nbsp;&nbsp;
<input type="radio" name="selection" id="rb_2" value="2"> Choice 2</input>
&nbsp;&nbsp;
<input type="radio" name="selection" id="rb_3" value="3"> Choice 3</input>
&nbsp;&nbsp;
<p>

<div style="text-indent:70pt;">
<button type="button" id="select">Make a Choice</button>
&nbsp;&nbsp;
<script>
function printChoice() {
    let choice = document.querySelector('input[name="selection"]:checked').value;
    window.alert("You selected: " + choice);
}

document.getElementById("select").addEventListener("click", function(event) {printChoice()});
</script>
</body>
</html>


14. Drawing on a Canvas Widget

For more complex drawing operations, there are libraries such as "paper.js" or "EaselJS".


15. Loading and Saving Text Files

For loading the contents of a local text-file into a JavaScript-program, the HTML-formular "<input type="file">" can be used.
I wanted a button though, with the functionality attached to it. To get this was unexpectedly difficult, but I finally got there:

<!DOCTYPE html>
<html>
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<p>
<div style="text-indent:100pt;">
<button type="button" id="mybutton">Load Textfile</button>
<script>

function load() {

    /* Read text file from button. Mixture of these two sources:
       https://stackoverflow.com/questions/13709482/how-to-read-text-file-in-javascript
       https://codepen.io/udaymanvar/pen/MWaePBY */

    let input = document.createElement('input');
    input.type = 'file';
    let textfilestring = "";
    input.onchange = _ => {
        if (input.files && input.files.length > 0 && input.files[0]) {
            let reader = new FileReader();
            reader.onload = function (e) {
                textfilestring = e.target.result;
                // We finally got the result:
                window.alert(textfilestring);
            };
            reader.readAsText(input.files[0]);
        }
    };
    input.click();
    input.remove();
}

document.getElementById("mybutton").addEventListener("click", function(event) {load()});
</script>
</body>
</html>

Saving a text-file locally was much easier:

<!DOCTYPE html>
<html>
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   <title>Test</title>
</head>
<body>
<p>
<div style="text-indent:100pt;">
<button type="button" id="view">View Text</button>
&nbsp;&nbsp;
<button type="button" id="save">Save Text</button>
<script>

textstring = "Hello World";

function view() {
    window.alert("The text is: " + textstring);
}

function saveTextstring(sometext) {
    const bb = new Blob([sometext ], { type: 'text/plain' });
    const a = document.createElement('a');
    a.download = "sometext.txt";
    a.href = window.URL.createObjectURL(bb);
    a.click();
    a.remove();
}

document.getElementById("view").addEventListener("click", function(event) {view()});
document.getElementById("save").addEventListener("click", function(event) {saveTextstring(textstring)});
</script>
</body>
</html>


Back to the computing-page


Author: hlubenow2 {at-symbol} gmx.net