Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

JavaScript Programming

Introduction to JavaScript

History of JavaScript

  • Brendan Eich developed at Netscape - it was called Mocha
  • 1995 - Released as LiveScript
  • 1995 - Renamed to JavaScript (to ride on the popularity of Java)
  • 1996 - Microsoft JScript
  • 1997 - First edition of ECMAScript standard (European Computer Manufacturers Association)
  • 1998 - Second edition
  • 1999 - Third edition
  • 4th edition never completed
  • 2009 - 5th edition
  • 2011 - 5.1 edition (part of "HTML5")
  • 2012 - TypeScript
  • 2015 - 6th edition (ECMAScript6 or ECMAScript 2015)

About JavaScript

  • In browser + DOM (Document Object Model)
  • On server (Node.js" %}
  • Embedded in other applications

JavaScript editors, IDEs

IDEs - Integrated Development Environment

Editors

alert

  • alert
  • script
  • ;

{aside} Probably the simplest way to see some action from JavaScript is to embed an alert() call in an html file. {/aside}

<html>
<head>
    <title>alert example</title>
</head>
<body>
<h1>Welcome to JavaScript</h1>

<script language="javascript">

alert("Hello World");

</script>

More HTML
</body>
</html>
  • Not really used any more
  • always put ; at the end of statements

Document.write

  • document.write
First line
<script>

document.write("<h1>Hello World</h1>");

</script>
Last line

  • script - javascript
  • document.write
  • document is the object representing the HTML document. The DOM.
  • Not really used any more

confirm

  • confirm
<h2>Before</h2>

<script>

if (confirm("Shall I print Hello World?")) {
    document.write("Hello World");
} else {
    document.write("OK, I won't print it.");
}

</script>

<h2>After</h2>

prompt

  • prompt
<h2>Before</h2>

<script>

var name = prompt("Your name:", "");
document.write("Hello ", name);

</script>

<h2>After</h2>

console

  • console.log

The better way to see messages from the JavaScript running in the browser is to use the console.log() function and open the console.

Open the console!
<script>

console.log("Hello World");

console.debug("A debug message");
console.info("An info message");
console.warn("A warning");
console.error("This is an error message");

</script>

To open the JavaScript console

  • Chrome Mac: Command-Option-J
  • Chrome Windows: Ctrl-Shift-J
  • Firefox Mac: Command-Option-K
  • Firefox Windows: Ctrl-Shift-K
  • Internet Explorer: F12
  • Safari: Command-Option-C

Run it with Node.JS

Run it in the editor

Separate script to its own file

Open the console!
<script src="console.js"></script>
console.log("Hello World");
$ node examples/js/console.js

Comments in JavaScript

  • /*
  • //
console.log("code 1");
// comment

console.log("code 2")
/* more
   comment
*/

console.log("code 3")

// console.log("/* hello */")

console.log("code 4")
  • To explain to the next developer why do we do something.
  • Explain algorithm.
  • Temporarily disable code for debugging.

Bad Comments in JavaScript

It is better to avoid the multiline comments /* */ Especially as most editors support the commenting out of a whole section of lines with just one keystroke.

console.log("code 1");
// comment

console.log("code 2")
/* more
   comment
*/

console.log("code 3")
/*
 console.log("/* hello */")
*/
console.log("code 4")
SyntaxError: unterminated string literal
.../examples/js/bad_comments.js:8
   console.log("/* hello */")
                           ^^
SyntaxError: Unexpected token ILLEGAL
    at exports.runInThisContext (vm.js:73:16)
    at Module._compile (module.js:443:25)
    at Object.Module._extensions..js (module.js:478:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Function.Module.runMain (module.js:501:10)
    at startup (node.js:129:16)
    at node.js:814:3

Literal values in JavaScript (numbers, strings, booleans, etc.)

  • Numbers (42, 2.3, NaN, Infinity, -Infinity)
  • Strings ("", '')
  • Booleans (true, false)
  • null
  • undefined
  • Objects (incl. Arrays, Functions)
console.log(42);
console.log(2.3);

console.log("hello");
console.log('world');

console.log(undefined);
console.log(null);
console.log(NaN);

console.log(Infinity);
console.log(-Infinity);


console.log(true);
console.log(false);
  • Numbers in JavaScript is 64-bit floating point (double)
  • Regular arithmetic issues 0.1+0.2 is not exactly 0.3

Examples for generating Infinite and NaN (not a number)

  • NaN
  • Infinite
console.log(2/0);       // Infinity
console.log(-2/0);      // -Infinity
console.log(2/-0);      // -Infinity
console.log(2/0 - 2/0); // NaN

var - variables in JavaScript

  • use strict
  • var
"use strict";

var user_name = 'Foo';
console.log(user_name); // "Foo"

var age = 42;
console.log(age);  // 42

age = 23;
console.log(age);  // 23

user_name = 1;
console.log(user_name); // 1

var email;
console.log(email); // undefined

email = 'foo@bar.com';
console.log(email);  // foo@bar.com
  • "use strict"; (later explained)
  • Declare variables using 'var'
  • Variable names start with letters, underscore (_), or the dollar sign.
  • Variable names can contain letters, underscore (_), the dollar sign, and digits.
  • camelCase is the recommended style in JavaScript, though I think long_names separated with underscores are nicer.

Variables without var

  • Works, variable are global here too.
  • What if we make a typo in one of the variable names? No one might notice, but the code will misbehave.
colour = "green";
console.log(colour);  // green
paint_house();
console.log(colour);  // green

// There are lots of lines of code here.
// So many lines that the next part is on another page:

function paint_house() {
    color = "blue";
}

use strict

  • use strict
"use strict";

colour = "green";
console.log(colour);  // green
paint_house();
console.log(colour);  // green

// There are lots of lines of code here.
// So many lines that the next part is on another page:

function paint_house() {
    color = "blue";
}

{% embed include file="src/examples/js/no_var_strict.txt)

use strict + var

"use strict";

var colour = "green";
console.log(colour);  // green
paint_house();
console.log(colour);  // green

// There are lots of lines of code here.
// So many lines that the next part is on another page:

function paint_house() {
    color = "blue";
}

{% embed include file="src/examples/js/var_strict.txt)

Scope of variables


<script src="scope_bare.js"></script>
<script src="scope_var.js"></script>
<script src="scope_let.js"></script>
<script src="scope_const.js"></script>

x = 1;


{
	console.log(`inside before: ${x}`);
	x = 2;
	console.log(`inside after: ${x}`);
}

console.log(`outside: ${x}`);

var x = 3;


{
	console.log(`inside before: ${x}`);
	var x = 4;
	console.log(`inside after: ${x}`);
}

console.log(`outside: ${x}`);

let x = 5;

console.log(`before: ${x}`);

{
	//console.log(`inside before: ${x}`); // Uncaught ReferenceError: Cannot access 'x' before initialization
	let x = 6;
	console.log(`inside after: ${x}`);
	x = 7;
	console.log(`inside end: ${x}`);

}

console.log(`outside: ${x}`);

const z = 10;

console.log(`before: ${x}`);

{
	console.log(`inside before: ${x}`);
	const z = 11;
	console.log(`inside after: ${x}`);
	z = 12; // Uncaught TypeError: 
	// console.log(`inside end: ${x}`);

}

console.log(`outside: ${x}`);

  • var
  • let
  • const

Exercise: Set up environment for web browser

  • Install either Chrome or Firefox if you don't have them yet.
  • Using Notepad or any other text editor create and .html file that will show and 'alert' and try it in your browser.
  • (Suggestion: Start by creating a directory in c:\ in Windows or in ~/ on Unix/Linux and put your files in that directory)

Exercise: Set up environment for command line

  • Install Node.js
  • Using Notepad or any other text editor (re-)create the console.js file and run it on the command line using node.
  • (On Windows you need to open Start/Run: cmd)

Exercise: Set up development environment

If you prefer to use another Editor/IDE, that's ok. Then insted of these steps, make sure you have similar capabilities there.

  • Install Atom
  • Open the directory where you've already saved the .html and .js files earlier using File/Open Project Folder
  • Install the Ternjs (atom-ternjs) package for JavaScript intelligence and check if it works properly. (In your .js file type in a string followed by a .)
  • Install the 'script' package to be able to run code from editor. Try to run the .js file.

Exercise: Hello World

  • Using the new Editor/IDE - open the console.js and run it from the editor
  • Create the console.html file too and open it with a browser
  • Create a hello.html that loads hello.js that ask the user for her name and then displays the result in the browser and on the console as well.

JavaScript basics

Numerical Operators

  • autoincrement ++, autodecrement --
  • shorthand +=, /=, *=, -=
"use strict";

console.log(19 + 23);   // 42
console.log(23 - 19);   // 4
console.log(23 * 19);   // 437
console.log(23 / 19);   // 1.2105263157894737
console.log(123 % 19);  // 9   (modulus)

var x = 19;
var y = 23;
console.log(x + y); // 42

x++;
console.log(x);   // 20

y--;
console.log(y);  // 22

x += 7;    // x = x + 7;
console.log(x);   // 27

x /= 3;   // x  = x / 3;
console.log(x);   // 9

  • %
  • ++
  • --
  • +=

String operations

  • trim
  • length
  • charAt
  • \t
  • \n
  • \
"use strict";

console.log("a" + "b");                         // ab
console.log("abc".length);                      // 3
console.log('<' + " a b c " + '>');             // < a b c >
console.log('<' + " a b c ".trim() + '>');      // <a b c>

console.log("this is a long string".charAt(3)); // s
console.log("this is a long string".charAt(0)); // t

var x = "Hello ";
var y = "World";
console.log(x + y); // Hello World
  • length is an attribute
  • trim() is a method
\t - tab
\n - newline
\" - to escape a quote
\\ - to escpae a backslash

Note: + acts both on numbers and on strings

String index and slice

  • length
  • slice
  • charAt
"use strict";

var str = "Hello World";
console.log(str[0]);        // H
console.log(str[1]);        // e
console.log(str.charAt(0)); // H
console.log('----');

var i;
for (i = 0; i < str.length; i++) {
    console.log(str[i]);
}

console.log(str.slice(3, 7));  // lo W

indexOf, lastIndexOf

  • indexOf
  • lastIndexOf
"use strict";

var str = "The black cat climbed the green tree.";
console.log(str.indexOf('a'));         // 6
console.log(str.indexOf('a', 7));      // 11
console.log(str.lastIndexOf('t'));     // 32
console.log(str.lastIndexOf('t', 31)); // 22

console.log(str.indexOf('cat'));       // 10
console.log(str.indexOf('dog'));       // -1

substr, slice, and substring

  • substring

  • substr

  • substr - (from, length?)

  • slice - (from, to?)

  • substring - (from, to?) (Use slice instead!)

"use strict";

var str = "The black cat climbed the green tree.";
console.log(str.substr(5,7));    // lack ca
console.log(str.slice(5,7));     // la

console.log(str.slice(22));      // the green tree.
console.log(str.substr(22));     // the green tree.

console.log(str.slice(10, -10));  // cat climbed the g
console.log(str.substr(10, -10)); // (empty string)

console.log(str.slice(-11, -6)); // green
console.log(str.substr(-11, -6)); // (empty string)

console.log(str.slice(-11, 31));  // green
console.log(str.slice(-11, 50));  // green tree.
console.log(str.substr(-11, 31)); // green tree.

Concatenate strings

  • concat
"use strict";

var name = 'Foo';
var mystr = "Hello " + name + ", how are you?";

console.log(mystr);   // Hello Foo, how are you?
console.log(name);    // Foo

var full = name.concat("Bar");
console.log(name);    // Foo
console.log(full);    // FooBar

Replace substring

  • replace
"use strict";

var str = "The black cat climbed the green tree.";
var dog = str.replace("cat", "dog");
console.log(str); // The black cat climbed the green tree.
console.log(dog); // The black dog climbed the green tree.

var str = str.replace("cat", "tiger");
console.log(str); // The black tiger climbed the green tree.

var str = str.replace("black", "");
console.log(str); // The  tiger climbed the green tree.

var str = str.replace(" ", "");
console.log(str); // The tiger climbed the green tree.

We'll see a more powerful version of this in the chapter about Regular expressions.

Mixing numbers and strings

"use strict";

var a = "23";
var b = "19";
console.log(a + b); // "2319"


var x = 23;
var y = "19";
console.log(x + y); // "2319"

var p = 23;
var q = 19;
console.log(p + q); // 42

In a nutshell: Don't do that!

Converting between numbers and strings

"use strict";

var a = "23";
var b = "19";
console.log(a + b); // "2319"
console.log(parseInt(a) + parseInt(b)); // 42

var p = 23;
var q = 19;
console.log(p + q); // 42
console.log(p.toString() + q.toString()); // "2319"
console.log(String(p) + String(q)); // "2319"

console.log(parseInt("23.42"));   // 23
console.log(parseFloat("23.42")); // 23.42

console.log(parseInt("2x3"));     // 2
console.log(parseInt("6.7x3"));   // 6
console.log(parseFloat("4.5x6")); // 4.5

console.log(Number("23"));      // 23
console.log(Number("23.12"));   // 23.12
console.log(Number("2x3"));     // NaN
console.log(Number("6.7x3"));   // NaN
console.log(Number("4.5x6"));   // NaN


  • parseInt
  • parseFloat
  • Number
  • toString
  • String

Convert octal, hexa

"use strict";

console.log(parseInt("0x11"));     //  17

console.log(parseInt("011"));      //  11 or 9 (depends on implementation)
console.log(parseInt("011", 10));  //  11
console.log(parseInt("011", 8));   //  9
console.log(parseInt("011", 16));  //  17

  • parseInt
  • octal
  • hex

Converting decimal to hexa

  • toString
  • toUpperCase
"use strict";

var a = 16;
console.log(a.toString(16)); // 10

var b = 129;
console.log(b.toString(16)); // 81

var a = 190;
console.log(a.toString(16)); // be

var a = 190;
console.log(a.toString(16).toUpperCase()); // BE

Browser IO (HTML)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">

  <title>Browser IO</title>
</head>
<body>

<input id="first_name">
<input id="last_name">
<button id="go">Say hi!</button>

<div id="result"></div>

<script src="browser-io.js"></script>

</body>
</html>

Browser IO (JavaScript)

function say_hi() {
    var fname = document.getElementById('first_name').value;
    var lname = document.getElementById('last_name').value;

    var html = 'Hello <b>' + fname + '</b> ' + lname;

    document.getElementById('result').innerHTML = html;
    return false;
}

document.getElementById('go').addEventListener('click', say_hi);

Exercise: Hello World on pressing button

Create an HTML page with a button on it. When the user presses the button display the text. "Hello World"

Solution: Hello World on pressing button

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">

  <title>Hello World</title>
</head>
<body>

<button id="go">Say hello</button>

<div id="result"></div>

<script src="hello_world.js"></script>

</body>
</html>
"use strict";

function greet() {
    document.getElementById('result').innerHTML = 'Hello World';
    return false;
}

document.getElementById('go').addEventListener('click', greet);

Exercise: Add two numbers

Create a web form that has two input fields and a button. The user can type js two numbers and when she clicks on a button, the page will show the sum of the numbers.

Solution: Add two numbers

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">

  <title>Add numbers</title>
</head>
<body>

<input id="x">
<input id="y">
<button id="go">+</button>

<div id="result"></div>

<script src="add_numbers.js"></script>

</body>
</html>
"use strict";

function add() {
    var x = Number(document.getElementById('x').value);
    var y = Number(document.getElementById('y').value);

    document.getElementById('result').innerHTML = x+y;
    return false;
}

document.getElementById('go').addEventListener('click', add);

Variable definition

// "use strict";

a = 1;
console.log(a); // 1

var b = 2;
console.log(b); // 2

var c;
console.log(c);         // undefined
console.log(typeof c);  // "undefined"

d = undefined;
console.log(d);         // undefined
console.log(typeof d);  // "undefined"

console.log(e);         // undefined
console.log(typeof e);  // "undefined"
var e = 3;


console.log(x); // ReferenceError: x is not defined

Conditionals in JavaScript

if statement

  • if
"use strict";

var y = 42;

if (y === 42) {
    console.log('y is 42');
}

// y is 42

Double equal (==) issues in JavaScript

  • ==
"use strict";

console.log(NaN == NaN);          // false

console.log(0 == '0');            // true
console.log(false == '0');        // true
console.log(null == undefined);   // true
console.log(' \t\r\n ' == 0);     // true

console.log('' == '0');           // false
console.log(0 == '');             // true

Compare values using == in JavaScript

  • ==
  • !=
"use strict";

console.log(2 == 2);                 // true
console.log(2 == 3);                 // false
console.log(2 == null);              // false
console.log(2 == undefined);         // false

console.log(undefined == undefined); // true
console.log(null == null);           // true

console.log(false == 'false');      // false

console.log(false == undefined);    // false
console.log(false == null);         // false

Compare values using === in JavaScript

  • ===
  • !==
"use strict";

console.log(2 === 2);                  // true
console.log(2 === 3);                  // false
console.log(2 === null);               // false
console.log(2 === undefined);          // false

console.log(undefined === undefined);  // true
console.log(null === null);            // true
console.log(NaN === NaN);              // false !!!

console.log('' === '0');               // false
console.log(0 === '');                 // false
console.log(0 === '0');                // false

console.log(false === 'false');       // false
console.log(false === '0');           // false

console.log(false === undefined);     // false
console.log(false === null);          // false
console.log(null === undefined);      // false

console.log(' \t\r\n ' === 0);        // false

Comparision operators

  • ==
  • !=
  • ===
  • !==
  • >
  • >=
  • <
  • <=

Comparision operators - examples

  • >
  • >=
  • <
  • <=
"use strict";

console.log(2 < 3);        // true
console.log('2' < '3');    // true
console.log('a' < 'b');    // true
console.log('c' < 'b');    // false
console.log('-----');

console.log(12 > 3);       // true
console.log(12 > '3');     // true
console.log('12' > 3);     // true
console.log('12' > '3');   // false
console.log('-----');

console.log('a' > '3');    // true
console.log('a' > 3);      // false
console.log('-----');

console.log(null < null);    // false
console.log(null <= null);   // true
console.log('-----');

console.log(null < undefined);   // false
console.log(null <= undefined);  // false
console.log(null > undefined);   // false
console.log(null >= undefined);  // false

Booleans: true and false

  • true
  • false
"use strict";

console.log(true);    // true
console.log(false);   // false
console.log(2 > 1);   // true
console.log(2 < 1);   // false


var x = 42;
if (x) {
    console.log("42 is true"); // 42 is true
}

Falsy values in JavaScript

  • false

Falsy:

  false
  null
  undefined
  ''   (The empty string)
  0  (The number)
  NaN
"use strict";

console.log('start');
if (false) {
  console.log('false');
}

if (null) {
  console.log('null');
}

if (undefined) {
  console.log('undefined');
}

if ('') {
  console.log('empty string ""');
}

if (0) {
  console.log('The number 0');
}

if (NaN) {
  console.log('Nan');
}
console.log('end');

Truthy values in JavaScript

  • true

Everything else is considered true:

The string " " with a single space
Infinity
The string "0"
The string "false"
"use strict";

console.log('start');

if (42) {
  console.log('The number 42');
}

if (' ') {
  console.log('The string " " with a single space');
}

if (Infinity) {
  console.log('Infinity');
}
if ('0') {
  console.log('The string "0"');
}

if ('false') {
  console.log('The string "false"');
}

console.log('end');

Logical operators

  • &&
  • ||
  • !
"use strict";

var x = true;
var y = true;
var z = false;
var q = false;

console.log(x && y); // true
console.log(x && z); // false
console.log('-----');

console.log(x || y); // true
console.log(x || z); // true
console.log(z || x); // true
console.log(z || q); // false
console.log('-----');

console.log(! x); // false
console.log(! z); // true

Toggle boolean

  • true
  • false
console.log('Start');

var b = true;

console.log(b);     // true

b = ! b;
console.log(b);     // false

b = ! b;
console.log(b);     // true

console.log('End');

Convert Truthy and Falsy values to boolean

  • !!
"use strict";

var x = undefined;
console.log(x);  // undefined

var y = !! x;
console.log(y);  // false


x = "hello";
console.log(x);  // hello
y = !! x;
console.log(y);  // true

Short circuit

"use strict";

var salary = 8000;
var money = 100000;

function check_standard_of_living() {
    if (money > 1000000 || salary++ > 10000) {
        console.log('I can live well.');
    }
    console.log('I have ' + money + ' in the bank and I get ' + salary + ' as salary.')
}

check_standard_of_living();
check_standard_of_living();
check_standard_of_living();

money = 2000000;
check_standard_of_living();
check_standard_of_living();
check_standard_of_living();
I have 100000 in the bank and I get 8001 as salary.
I have 100000 in the bank and I get 8002 as salary.
I have 100000 in the bank and I get 8003 as salary.
I can live well.
I have 2000000 in the bank and I get 8003 as salary.
I can live well.
I have 2000000 in the bank and I get 8003 as salary.
I can live well.
I have 2000000 in the bank and I get 8003 as salary.

Better not to use ++, -- auto-increment and auto-decrement inside other expressions.

if - else

  • if
  • else
"use strict";

var x = 23;
var y = 42;

if (x < y) {
    console.log(x + ' is smaller than ' + y);
} else {
    console.log(x + ' is NOT smaller than ' + y);
}

// 23 is smaller than 42
if () {
    ...
} else {
    if () {
        ...
    } else {
        if () {
            ...
        }
    }
}

else if

  • else if
  • ===
"use strict";

var x = 23;
var y = 42;

if (x === y) {
  console.log("equal");
} else if (x < y) {
  console.log("x is smaller than y");
} else {
  console.log("x is bigger than y");
}

// x is smaller than y

Switch (case) in JavaScript

  • switch
  • case
  • default
  • break
"use strict";

var n = 42;

switch (n) {
  case 1: {
    console.log(1);
    break;
  };
  case 42: {
    console.log(42);
  };
  case 'other': {
    console.log('other');
  };
  default: {
    console.log('default')
  };

}

// 42
// other
// default
  • You'd better call "break" at the end of each "case" statement or this will fall through and will execute all the lower cases without checking their condition.
  • Switch uses === for comparision.
  • We can put variables instead of the fixed values in the 'case' statements.
  • If the same value appears in more than one 'case', only the first one will match.

Math.round

  • Math
  • round
"use strict";

var v = "3.14159265359";
console.log(v);                       // 3.14159265359
console.log(100 * v);                 // 314.159265359

console.log(Math.round(v));           // 3
console.log(Math.round(100 * v)/100); // 3.14

console.log(Math.round(3.9));         // 4
console.log(Math.round(3.5));         // 4
console.log(Math.round(3.49999999));  // 3

Rounding up a float to integer (ceil)

  • ceil
let pi = 3.14;
var intvalue = Math.ceil( pi );

Rounding down a float to integer (floor)

  • floor
let pi = 3.14;
var intvalue = Math.floor( pi );

Converting float to integer (trunc)

  • floor
  • round
  • trunc
let pi = 3.14;
var intvalue = Math.round( pi );

// `Math.trunc` was added in ECMAScript 6
var intvalue = Math.trunc( pi );

Math.random

  • random
"use strict";

var v = Math.random();
console.log(v);    // 0.7282267780974507

Throw a dice (random integers 1-6)

  • random
  • floor
"use strict";

var v = Math.floor( 6 * Math.random() );
console.log(v);    // 2

Exercise: Calculator

Create a web page with 3 input fields for 2 numbres and an operator such as +, -, *, or /. When the user clicks on the "Calculate" button, take the 3 values and calculate the result of the expression.

Solution: Calculator

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">

  <title>Calculator</title>
</head>
<body>

x: <input id="x">
operator: <input id="op">
y: <input id="y">

<button id="go">Calculate</button>

<div id="result"></div>

<script src="calculator.js"></script>

</body>
</html>
"use strict";

function calculate() {
    var x = Number(document.getElementById('x').value);
    var y = Number(document.getElementById('y').value);
    var op = document.getElementById('op').value;
    var result;

    switch (op) {
        case '+' : {
            result = x+y;
            break;
        };
        case '*' : {
            result = x*y;
            break;
        };
        case '-' : {
            result = x-y;
            break;
        };
        case '/' : {
            result = x/y;
            break;
        };
    };

    document.getElementById('result').innerHTML = result;
    return false;
}

document.getElementById('go').addEventListener('click', calculate);

Exercise: Guess number

When the page is loaded the computer "thinks" about a random whole number between 1 and 200, and displays an input box and a button "guess". The user types in a number and the computer will check if the given number is "smaller" or "larger" than the number it "though" about, or if they happen to be equal.

Once that's done, change the solution so it will count how many times has the user guessed before the coreect number was found.

Solution: Guess number

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">

  <title>Guess Number</title>
</head>
<body>

<input id="n">
<button id="go">Guess</button>

<div id="result"></div>

<script src="guess_number.js"></script>

</body>
</html>
"use strict";

var hidden = Math.round(Math.random()*200+0.5);
var counter = 0;
console.log(hidden);

function check_guess() {
    counter++;
    var n = Number(document.getElementById('n').value);
    var result = 'equal after ' + counter + ' guesses';
    if (n < hidden) {
        result = n + ' is less than our number';
    }
    if (n > hidden) {
        result = n + ' is greater than our number';
    }
    document.getElementById('result').innerHTML = result;
    return false;
}

document.getElementById('go').addEventListener('click', check_guess);

Arrays in JavaScript

for-loop

  • for
for (INITIALIZE;   CONDITION;   STEP) {

}
"use strict";

var i,j;

for (i=0; i < 6; i++) {
    console.log(i);
}

console.log('---');

for (j=9; j > 6 ; j--) {
    console.log(j);
}

while loop

  • while
while (CONDITION) {

}
"use strict";

var n = 1;
while (n < 7) {
    n++;
    console.log(n);
}
2
3
4
5
6
7

Break out from while loop in JavaScript

  • break
"use strict";

var n = 1;
while (n < 7) {
    n++;
    console.log(n);
    if (n >= 4) {
      break;
    }
}
2
3
4

An infinite while loop

"use strict";

while (true) {
    ...
    if (CONDITION) {
        break;
    }
}

Continue to next in while loop in JavaScript

  • continue
"use strict";

var n = 1;
while (n < 7) {
  n++;
  if (n === 5) {
      continue;
  }
  console.log(n);
}
2
3
4
5
6
7

do-while loop in JavaScript

  • do while

The loop is executed at least once.

"use strict";

var n = 1;
do {
    n++;
    console.log(n);
} while (n < 1);

For example you ask a question and let the user guess. Every time you compare the answer to the expected answer. You will need to get the value from the user before the first compare, and then if it fails, ask the user again. If you use plain "while" then you'll have to read from the user once before the while-loop and then inside the loop too. OTOH if you use the "do-while" loop, it is enought to ask in the do-block.

new Array

  • new
  • Array
  • for
  • length
"use strict";

var names = new Array("Foo", "Bar", "Moose");
console.log(names);    // [ "Foo", "Bar", "Moose" ]
console.log(names[1]); // "Bar"

var i;
for (i = 0; i < names.length; i++) {
    console.log(names[i]);
}

Literal array: []

  • []
"use strict";

var fruits = ["apple", "banana", "peach"];
var i;
console.log(fruits);     // [ "apple", "banana", "peach" ]
console.log(fruits[1]);  // "banana"
for (i = 0; i < fruits.length; i++) {
    console.log(fruits[i]);
}

Enlarge array with elements

"use strict";

var names = ['Foo', 'Bar', 'Baz'];
console.log(names);         // ["Foo", "Bar", "Baz"]
console.log(names[0]);      // "Foo"

names[3] = 'Moo';
console.log(names[3]);      // "Moo"
console.log(names.length);  // 4

names[6] = "Other";
console.log(names.length);  // 7
console.log(names[4]);      // undefined
console.log(names[6]);      // "Other"
console.log(names);         // [ "Foo", "Bar", "Baz", "Moo", <2 empty slots>, "Other" ]

JavaScript Arrays - pop - push

  • pop
  • push
"use strict";

var names = [ "foo" ];
console.log(names);   // [ "foo" ]

names[1] = "bar";
console.log(names);   // [ "foo", "bar" ]

names.push("moo");
console.log(names);  // [ "foo", "bar", "moo" ]

names.push("qux", "zorg");
console.log(names); // [ "foo", "bar", "moo", "qux", "zorg" ]

var last = names.pop();
console.log(last);  // "zorg"
console.log(names); // [ "foo", "bar", "moo", "qux" ]

JavaScript Arrays - shift - unshift

  • shift
  • unshift
"use strict";

var names = [ "foo", "bar", "moo", "qux" ];

var first = names.shift();
console.log(first); //  "foo"
console.log(names); // [ "bar", "moo", "qux" ]

names.unshift("boo");
console.log(names); // [ "boo", "bar", "moo", "qux" ]

Two dimensional array (matrix)

  • matrix
"use strict";

var entries = [
    ["Foo", 123],
    ["Bar", 345],
    ["Moo", 230],
];
var i;
for (i = 0; i < entries.length; i++) {
    console.log(entries[i][0] + ' - ' + entries[i][1]);
}

// Foo - 123
// Bar - 345
// Moo - 230

For-in loop on array

  • for
  • in

We don't have to use the C-style for-loop on arrays. We can use the simpler, for-in construct. It will iterate over the index of the array.

"use strict";

var names = ["Foo", "Bar", "Qux"];
var v;
for (v in names) {
    console.log(v);
}
// 0
// 1
// 2

ForEach loop on array

  • forEach

Another way to iterate over the elements of an array is to use the forEach method of the array. It gets a function as an argument and it will call that function with each one of the values of the array.

"use strict";

var names = ["Foo", "Bar", "Qux"];
names.forEach(function(v) {
    console.log(v);
})
// Foo
// Bar
// Qux

Reverse array

  • reverse
"use strict";

var names = ['Foo', 'Bar', 'Morse'];

console.log(names);   // [ 'Foo', 'Bar', 'Morse' ]
names.reverse();
console.log(names);   // [ 'Morse', 'Bar', 'Foo' ]

Concatenate arrays

  • concat
"use strict";

var names = ['Foo', 'Bar', 'Moo'];
var people = ['Joe', 'Mary'];

var joint_list = names.concat(people, 'Morgo', ['Bare', 'Array']);
console.log(names);       // [ 'Foo', 'Bar', 'Moo' ]
console.log(people);      // [ 'Joe', 'Mary' ]
console.log(joint_list);
// [ 'Foo', 'Bar', 'Moo', 'Joe', 'Mary', 'Morgo', 'Bare', 'Array' ]

Concatenate array with object

"use strict";

var names = ['Foo', 'Bar'];

console.log(names.concat({ x:'y'})); // [ 'Foo', 'Bar', { x: 'y' } ]
console.log(names.concat(/regex/));  // [ 'Foo', 'Bar', /regex/ ]

Concatenate array is shallow

"use strict";

var names = [
    ['Foo', 23],
    ['Bar', 17]
];

var other = names.concat('Joe');
console.log(names);    // [ [ 'Foo', 23 ], [ 'Bar', 17 ] ]
console.log(other);    // [ [ 'Foo', 23 ], [ 'Bar', 17 ], 'Joe' ]

names[0][0] = 'Moooo';
console.log(names);    // [ [ 'Moooo', 23 ], [ 'Bar', 17 ] ]
console.log(other);    // [ [ 'Moooo', 23 ], [ 'Bar', 17 ], 'Joe' ]

Array indexOf lastIndexOf

  • indexOf
  • lastIndexOf
"use strict";

var names = ['Foo', 'Bar', 'Morse', 'Foo', 'Bar', 'Luke', 'Lea', 'Han Solo'];

console.log(names.indexOf('Foo'));        // 0
console.log(names.indexOf('Foo', 1));     // 3
console.log(names.lastIndexOf('Foo'));    // 3
console.log(names.lastIndexOf('Foo', 2)); // 0

console.log(names.indexOf('Vader'));      // -1

Array slice (range) or splice

  • slice
  • splice

slice(from, to) - shallow copy of a range defined by its end points.

splice(from, length) - shallow copy of a range defined by the number of elements in it

"use strict";

var names = ['Foo', 'Bar', 'Morse', 'Luke', 'Lea', 'Han Solo'];

console.log(names.slice(3, 5));   // [ 'Luke', 'Lea']
console.log(names.splice(2, 3));  // ['Morse', 'Luke', 'Lea']

Split string, join array

  • split
  • join
"use strict";

var names = ['Foo', 'Bar', 'Morse', 'Foo', 'Bar', 'Luke', 'Lea', 'Han Solo'];

var str = names.join(':');
console.log(str); // Foo:Bar:Morse:Foo:Bar:Luke:Lea:Han Solo

var n = str.split(':');
console.log(n);
// [ 'Foo', 'Bar', 'Morse', 'Foo', 'Bar', 'Luke', 'Lea', 'Han Solo' ]

Deep copy with JSON

  • JSON
JSON.parse(JSON.stringify(o));

Exercise: Count digits

Given an array of strings in which every string contains numbers separated by spaces, count how many times each digit appears?

"use strict";

var numbers = [
    '123 124    56',
    '68 23 '
];

...

Expected output:

0 0
1 2
2 3
3 2
4 1
5 1
6 2
7 0
8 1
9 0

Solution: Count digits

"use strict";

var numbers = [
    '123 124    56',
    '68 23 '
];
var i, j, counter = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

for (i = 0; i < numbers.length; i++ ) {
    for (j = 0; j < numbers[i].length; j++) {
        if (numbers[i][j] !== ' ') {
            counter[ numbers[i][j] ]++;
        }
    }
}
for (i = 0; i < 10; i++) {
    console.log(i,  counter[i]);
}

Exercise: Count characters

Given a string count how many time each character appears. See this skeleton:

"use strict";

var string = "hello world";

Solution: Count characters

"use strict";

var string = "hello world";
var i, j;
var counter = [];
var chars = [];

for (i = 0; i < string.length; i++) {
    // console.log(string[i]);
    var found = false;
    for (j = 0; j < chars.length; j++) {
        if (chars[j] == string[i]) {
            counter[j]++;
            found = true;
            break;
        }
    }
    if (! found) {
        chars.push(string[i]);
        counter.push(1);        
    }
}

for (i = 0; i < chars.length; i++) {
    console.log(chars[i],  counter[i]);
}

Exercise: Number guessing - history

In the previous chapter we had an exercise in which the computer "thought" a number, and the user had to guess it.

  • Show the history of guesses.
  • Show if we are getting closer (warm) or farther away (cold) relative to the previous guess.

Solution: Number guessing - history

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">

  <title>Guess Number</title>
</head>
<body>

<input id="n">
<button id="go">Guess</button>

<div id="result"></div>

<script src="guess_number_history.js"></script>

</body>
</html>
"use strict";

var hidden = Math.round(Math.random()*200+0.5);
var guess_history = [];
var i;

console.log(hidden);

function check_guess() {
    var n = Number(document.getElementById('n').value);
    var result = 'equal after ' + guess_history.length + ' guesses.';
    if (n < hidden) {
        result = n + ' is less than our number';
    }
    if (n > hidden) {
        result = n + ' is greater than our number';
    }
    if (guess_history.length > 0 && n !== hidden) {
        //console.log(guess_history[ ]);
        if (Math.abs(guess_history[guess_history.length - 1] - hidden) < Math.abs(n - hidden)) {
            result += ' (<b>cold</b>)';
        } else {
            result += ' (<b>warm</b>)';
        }
    }
    guess_history.push(n);
    result += '<br>';
    result += '<b>History:</b><br>'
    for (i = guess_history.length-1; i >=0; i--) {
        result += guess_history[i] + '<br>';
    }
    document.getElementById('result').innerHTML = result;
    return false;
}

document.getElementById('go').addEventListener('click', check_guess);

Exercise: Number guessing

Once that works, add a new button allowing the user to start a new game once one was finished.

Once that works allow the user to "give up" the current game and start a new one.

Exercise: Reverse the number guessing game

In this version you think about a number between 1-200 and press the "start" button. Then the computer guesses and you have to tell it if the guessed number is the one you thought about, or if it is smaller or larger than what you thought about. For this you might need to add 3 new buttons. If your answer was "smaller" or "bigger", the computer guesses again. How many guesses does your program need?

Solution: Reverse the number guessing game

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">

  <title>Guess Number</title>
</head>
<body>

<button id="go">Start</button>
<button id="bigger">Bigger</button>
<button id="smaller">Smaller</button>
<button id="bingo">Bingo</button>

<div id="result"></div>

<script src="reverse_number_guessing.js"></script>

</body>
</html>
"use strict";

var guess = null;
var min = null;
var max = null;
var lower_limit = 1;
var upper_limit = 200;



function start_guessing() {
    min = lower_limit;
    max = upper_limit;
    show();
}
function guess_smaller() {
    max = guess;
    show();
}
function guess_bigger() {
    min = guess;
    show();
}

function bingo() {
    document.getElementById('result').innerHTML = "Yeah!";
    return false;
}

function show() {
    guess = Math.round((max+min)/2);
    document.getElementById('result').innerHTML = guess;
    return false;
}

document.getElementById('go').addEventListener('click', start_guessing);
document.getElementById('bigger').addEventListener('click', guess_smaller);
document.getElementById('smaller').addEventListener('click', guess_bigger);
document.getElementById('bingo').addEventListener('click', bingo);

JavaScript functions

Function statements

  • function
"use strict";

function add(x, y) {
    var z = x+y;
    return z;
}

console.log(add(2, 3));    // 5
console.log(add(19, 23));  // 42

Function expressions (Anonymous functions)

"use strict";

var add = function (x, y) {
    var z = x+y;
    return z;
}

console.log(add(2, 3));    // 5

Unknown number of function arguments

  • arguments
"use strict";

var sum = function () {
    var i, s = 0;
    for (i=0; i < arguments.length; i++) {
        s += arguments[i];
    }
    return s;
}
console.log(sum(2, 5, 1)); // 8

Assign function

"use strict";

var add = function (a, b) {
    return a+b;
}

var sum = add;

console.log(add(2, 3));  // 5
console.log(sum(3, 4));  // 7

console.log(sum);        // [Function]
// function add(a, b) {
//     return a+b;
// }

We can assign the name of a function to a variable. Now we have the same function with two names. We can call both using the function_name() notation. We can even print the source code of the function in either of the variables.

Passing functions as parameter of another function

var add = function (a, b) {
    return a+b;
}
var subtract = function (a, b) {
    return a-b;
}

var handle_data = function (func) {
    // get data from user or other external source
    var x = 2;
    var y = 3;
    return func(x, y);
}

console.log(handle_data(add));       // 5
console.log(handle_data(subtract));  // -1

Recursive function

"use strict";

var fact = function (n) {
    if (n === 1) {
        return 1;
    }
    return n * fact(n-1);
}

console.log(fact(4)); // 24

Dispatch table

"use strict";

var dispatch_table = {
    '+' : function (a, b) {
        return a+b;
    },
    '-' : function (a, b) {
        return a-b;
    }
};

function run(dt, op, x, y) {
    if (! dt[op]) {
        console.log("Invalid operator: " + op);
        return;
    }
    return dt[op](x, y);
}

console.log(run(dispatch_table, '-', 2, 3));  // -1
console.log(run(dispatch_table, '+', 2, 3));  // 5
console.log(run(dispatch_table, '*', 2, 3));  // Invalid operator: *

Variable scope

  • scope
"use strict";

var x = 42;

var add = function (a, b) {
    var x = a + b;      // private x
    return x;
}

var multiply = function (a, b) {
    x = a * b;          // global x
    return x;
}

console.log(x);              // 42
console.log(add(2, 3));      //  5
console.log(x);              // 42
console.log(multiply(2, 4)); //  8
console.log(x);              //  8

There is global scope and there is local scope inside functions.

Scope in if block

"use strict";

var x = 42;
console.log(x);       // 42
if (true) {
    var x = 23;       // var does not do anything here
    console.log(x);   // 23
}
console.log(x);       // 23

if-blocks, don't create local scopes.

Variable in for loop

"use strict";

// var i = 5;

for (var i = 0; i < 3; i++) {
    console.log(i);
}
console.log('--');
console.log(i);

for-oops, don't create local scopes.

Immediate Execution using ()

  • ()
"use strict";

var greeting = function () {
    return "hi there";
}

console.log(greeting);    // [Function]
console.log(greeting());  // hi there

var hw = function () {
    return "Hello World";
}();

console.log(hw);    // Hello World

Immediate Execution with parameters using ()

  • ()
"use strict";

var greeting = function (name) {
    return "hi " + name;
}

console.log(greeting);         // [Function]
console.log(greeting('Foo'));  // hi Foo

var hw = function (name) {
    return "Hello " + name;
}('Bar');

console.log(hw);    // Hello Bar

Private Global Scope

(function() {
    "use strict";

    var me = 'Foo';
    var greet = function (name) {
        return 'Hello ' + name;
    }
    var res = greet(me);

    console.log(res);  // Hello Foo
}())

Exercise: Reverse Polish Calculator

A regular "inline" calcularo accespts the operator between two operands: 2 + 3. If we have more operators and operands such a 2 + 3 * 7, we (and the computer) need to know the precedence of the operators.

In a Polish calculator we would write the operator before the operands: + 2 3. In a Reverse Polish Calculator we would write the operator after the operands: 2 3 + or 2 3 7 * +. Once we wrote down an expression the order of computation is clear. (First apply * to 3 and 7 and the apply + to the result and 2)

In this exercise you are requeted to implement a Reverse Polish Calculator that can handle +, -, *, /, and that will remove and display the last value when an = character is entered.

Reverse Polish Calculator in JavaScript

"use strict";

function RPN() {
    var stack = [];
    var f = function() {
    };
    f.size = function() {
        return stack.length;
    }
    f.exe = function(v) {
        if (v === '+') {
            var res = stack.pop() + stack.pop();
            stack.push(res);
            return;
        }
        if (v === '*') {
            var res = stack.pop() * stack.pop();
            stack.push(res);
            return;
        }
        if (v === '-') {
            var res = stack.pop() - stack.pop();
            stack.push(res);
            return;
        }
        if (v === '/') {
            var res = stack.pop() / stack.pop();
            stack.push(res);
            return;
        }
        if (v === '=') {
            return stack.pop();
        }
        stack.push(v);
    };
    return f;
}

var r = RPN();
r.exe(2);
r.exe(3);
r.exe(4);
console.log(r.size());     // 3
r.exe('+');
r.exe('*');
console.log(r.exe('='));   // 14
console.log(r.size());     // 0
r.exe(6);
r.exe(2);
r.exe('-');
console.log(r.exe('='));   // -4

Order

function some_function() {
    console.log("in some_function");
}

console.log("before");
some_function();
console.log("after");
export default function fibo(n) {
	if (n == 1) {
		return [1];
	}
	if (n == 2) {
		return [1, 1];
	}
	let numbers = [1]
	for (let c = 3; c <= n; c++) {
		numbers.push(numbers[-1] + numbers[-2]);
	}
	return numbers;
	
}

JavaScript Objects

new empty object

"use strict";

var MyThing = function() {
}
var t = new MyThing;
console.log(MyThing); // function MyThing()
console.log(t); // Object {  }

t.a = 23;
console.log(t);
t.doit = function() {
    console.log('doit');
    console.log(this);
    console.log(this.a);
}
t.doit();

new Objects

"use strict";

var MyThing = function() {
    this.smile = function() {
        console.log("This thing can smile!");
    }
}
var t = new MyThing;
console.log(MyThing); // function MyThing()
console.log(t);       // Object {  }
t.smile();            // "This thing can smile!"

new Object with attribute

"use strict";

var MyPerson = function(fname) {
    this.first_name = fname;
}

var m = new MyPerson('Foo');
console.log(MyPerson); // function MyPerson()
console.log(m);        // Object {  }

Literal Objects

  • object
  • hash
  • dictionary

Keys in the object don't need to be quoted, unless they contain special characters, like a dash.

"use strict";

var email = {
   "from"      : "js@bar.com",
   "to"        : [ "foo@bar.com", "qux@bar.com" ],
   "subject"   : "Hello World",
   "mime-type" : "text"
};
console.log(email);
Object { from: "js@bar.com", to: Array[2], subject: "Hello World", mime-type: "text" }

Dumping data structures (for debugging)

  • JSON
  • Dump
"use strict";

var user = {
   'name' : 'Foo Bar',
   'emails' : [
       'foo@bar.com',
       'foobar@gmail.com'
   ]
};
console.log(JSON.stringify(user, undefined, 2));
"{
  "name": "Foo Bar",
  "emails": [
    "foo@bar.com",
    "foobar@gmail.com"
  ]
}"

Access JavaScript object attributes

"use strict";

var email = {
   "from"      : "js@bar.com",
   "to"        : [ "foo@bar.com", "qux@bar.com" ],
   "subject"   : "Hello World",
   "mime-type" : "text"
};
console.log(email["from"]);      // "js@bar.com"
console.log(email["mime-type"]); // "text"


console.log(email.from);     // "js@bar.com"
// console.log(email.mime-type);  // ReferenceError: type is not defined


email["text"] = "Content";
console.log(JSON.stringify(email, undefined, 2));
"{
  "from": "js@bar.com",
  "to": [
    "foo@bar.com",
    "qux@bar.com"
  ],
  "subject": "Hello World",
  "mime-type": "text",
  "text": "Content"
}"

Change JavaScript object attributes

"use strict";

var email = {
   "from"      : "js@bar.com",
   "to"        : [ "foo@bar.com", "qux@bar.com" ],
   "subject"   : "Hello World",
   "mime-type" : "text"
};
console.log(email);
email["subject"] = "About JavaScript";
console.log(email);

email["text"] = "Content";
console.log(email);

Add JavaScript object attributes

"use strict";

var email = {
   "from"      : "js@bar.com",
   "to"        : [ "foo@bar.com", "qux@bar.com" ],
};
console.log(email);

email["text"] = "Content";
console.log(email);

Delete property from object

  • delete
"use strict";

var x = {
  'a' : 1,
  'b' : 2
};
console.log(x);           // Object {a: 1, b: 2}
var ret = delete(x['a']);
console.log(x);           //Object {b: 2}
console.log(ret);         // true

var ret = delete(x['c']);
console.log(x);           //Object {b: 2}
console.log(ret);         // true

for-in loop on JavaScript object

  • for in
  • hasOwnProperty
"use strict";

var email = {
   "from"      : "js@bar.com",
   "to"        : [ "foo@bar.com", "qux@bar.com" ],
   "subject"   : "Hello World",
   "mime-type" : "text"
};
console.log(email);

var k;
for (k in email) {
   if (! email.hasOwnProperty(k)) {
      continue;
   }
   console.log('k:', k);
   console.log('v:', email[k]);
}

Count words

"use strict";

var text = 'this is a constructor this is not';

var words = text.split(/\s+/);
var count = {};
var i;
for (i in words) {
    var word = words[i];
    if (count[word] === undefined) {
        count[word] = 0;
    }
    count[word]++;
}
console.log(count);
// Object { this: 2, is: 2, a: 1, constructor: NaN, not: 1 }

'constructor' needs special treatment as that attribute is already part of the object.

Count words fixed

"use strict";

var text = 'this is a constructor this is not';

var words = text.split(/\s+/);
var count = {};
var i;
for (i in words) {
    var word = words[i];
    if (typeof count[word] !== 'number') {
        count[word] = 0;
    }
    count[word]++;
}
console.log(count);
// Object { this: 2, is: 2, a: 1, constructor: 1, not: 1 }

keys of an object

  • keys
"use strict";

var count = {
    'foo': 23,
    'bar': 42,
    'morse':100
};

console.log(Object.keys(count)); // [ 'foo', 'bar', 'morse' ]

var keys = Object.keys(count);
var i;
for (i = 0; i < keys.length; i++) {
    console.log(i, keys[i], count[ keys[i] ]);
}
// 0 'foo' 23
// 1 'bar' 42
// 2 'morse' 100

Advanced JavaScript

Stringify NaN, Infinite, and null

  • NaN
  • Infinite
  • null
"use strict";

var x = 2/0;
var y = -2/0;
var z = x+y;
var n = null;

console.log(JSON.stringify({ "x" : x }, undefined, 2));
console.log(JSON.stringify({ "y" : y }, undefined, 2));
console.log(JSON.stringify({ "z" : z }, undefined, 2));
console.log(JSON.stringify({ "n" : n }, undefined, 2));
{
  "x": null
}
{
  "y": null
}
{
  "z": null
}
{
  "n": null
}

JSON parsing NaN, Infinite, and null

<script>
var str = '{ "v" : 42 }';
console.log(JSON.parse(str)); // Object {v: 42} 

str = '{ "n" : null }';
console.log(JSON.parse(str)); // Object {n: null} 

str = '{ "x" : NaN }';
console.log(JSON.parse(str)); // Uncaught SyntaxError: Unexpected token N 

str = '{ "y" : Infinite }';
console.log(JSON.parse(str)); // Uncaught SyntaxError: Unexpected token I
</script>
Object { v: 42 } json_parse_nan.html:3:0
Object { n: null } json_parse_nan.html:6:0
SyntaxError: JSON.parse: unexpected character at line 1 column 9 of the JSON data

JSON parsing NaN, Infinite, and null (Node.js" %}

"use strict";

var str = '{ "v" : 42 }';
console.log(JSON.parse(str)); // Object {v: 42} 

str = '{ "n" : null }';
console.log(JSON.parse(str)); // Object {n: null} 

str = '{ "x" : NaN }';
console.log(JSON.parse(str)); // Uncaught SyntaxError: Unexpected token N 

str = '{ "y" : Infinite }';
console.log(JSON.parse(str)); // Uncaught SyntaxError: Unexpected token I
{ v: 42 }
{ n: null }
undefined:1
{ "x" : NaN }
        ^
SyntaxError: Unexpected token N

typeof

  • typeof
"use strict";

console.log(typeof true);          // boolean
console.log(typeof "hello world"); // string
console.log(typeof 42);            // number

var answer = 52;
console.log(typeof answer);        // number

var name;
console.log(typeof name);          // string

console.log(typeof 1/0);           // Nan
console.log(typeof undefined);     // undefined
console.log(typeof null);          // object

typeof and null

"use strict";

check_null(null);
check_null({});
check_null(42);

function check_null(x) {
    console.log(typeof x);
    console.log(x === null ? "null" : "not null");
    console.log(x && typeof x === 'object' ? "object" : "null");
}

Delayed (scheduled) execution - setTimeout

  • setTimeout
"use strict";

function later() {
  console.log('later');
}

setTimeout(later, 1000);
console.log('now');

Recurring execution - setInterval

  • setInterval
"use strict";

function later() {
    console.log('later');
}

setInterval(later, 1000);
console.log('now');

Stop recurring execution - clearInterval

  • clearInterval
"use strict";

function later() {
  console.log('later');
}
function stop() {
    console.log('clearing now');
    clearInterval(timer);
}

var timer = setInterval(later, 1000);
setTimeout(stop, 6000);
console.log('now');

Dates

  • Date
"use strict";

var d = new Date;
console.log(d);   // Mon Jul 20 2015 14:46:51 GMT+0300 (IDT)
console.log(Math.abs(new Date() - d));  // 25
setTimeout(show, 10);

d = new Date('1995-12-17T03:24:00');
console.log(d);  // Sun Dec 17 1995 05:24:00 GMT+0200 (IST)

function show() {
    console.log(Math.abs(new Date() - d));  // 618222446613
}

sort

  • sort
  • localCompare
"use strict";

var names = ['Foo', 'Bar', 'Moose', 'Zorg', 'Baz', 'Moo'];
console.log(JSON.stringify(names, undefined, 2));
//  ['Foo', 'Bar', 'Moose', 'Zorg', 'Baz', 'Moo'];

names.sort();
console.log(JSON.stringify(names, undefined, 2));
//  ['Bar', 'Baz', 'Foo', 'Moo', 'Moose', 'Zorg'];

var numbers = [3, 12, 4];
console.log(JSON.stringify(numbers, undefined, 2));
// [3, 12, 4];
numbers.sort();
console.log(JSON.stringify(numbers, undefined, 2));
// [12, 3, 4];

numbers.sort(function(a, b) { return a-b });
console.log(JSON.stringify(numbers, undefined, 2));
// [3, 4, 12];

var names = ['Foo', 'Bar', 'Moose', 'Zorg', 'Baz', 'Moo'];
names.sort(function(a, b) { return a.length - b.length });
console.log(JSON.stringify(names, undefined, 2));
// ['Foo', 'Bar', 'Baz', 'Moo', 'Zorg', 'Moose'];

names.sort(function(a, b) { return a.length - b.length || a.localeCompare(b)});
console.log(JSON.stringify(names, undefined, 2));
// ['Bar', 'Baz', 'Foo', 'Moo', 'Zorg', 'Moose'];

sort object

"use strict";

var people = {
    "11" : {
       "name" : "Foo",
       "age"  : 30
    },
    "20" : {
       "name" : "Bar",
       "age"  : 28
    }
};
console.log(JSON.stringify(people, undefined, 2));

for (var i in people) {
    console.log(i);  // 11  20
}
var ids = [];
for (var i in people) {
    ids.push(i);
}
console.log(JSON.stringify(ids, undefined, 2));
ids.sort(function(a, b) { return people[a]['age'] - people[b]['age'] } );
console.log(JSON.stringify(ids, undefined, 2));


var names = ['Foo', 'Bar'];
for (var i in names) {
    console.log(i); // 0 1
}

sort datestrings

"use strict";

var dates = ['2013-04-02', '2012-05-06', '2014-10-10'];
console.log(dates);
console.log(dates.sort());
console.log(dates);
var dates = [
    {
        'd' : '2013-04-02',
        'n' : 'one'
    },
    {
        'd' : '2012-05-06',
        'n' : 'two'
    },
    {
        'd' : '2014-10-10',
        'n' : 'three'
    }
];
console.log(JSON.stringify(dates, undefined, 2));
dates.sort(function(a, b) { return a['d'].localeCompare(b['d']) });
console.log(JSON.stringify(dates, undefined, 2));

map

  • map
"use strict";

var numbers = [2, 5, 3, 7];
function double(n) {
    return n*2;
}

var doubles = numbers.map(double);
console.log(numbers);  // [2,  5, 3,  7]
console.log(doubles);  // [4, 10, 6, 14]

var triples = numbers.map(function(n) { return n * 3 });
console.log(triples);  // [6, 15, 9, 21]

Closures in JavaScript

"use strict";

function create_incrementer(n) {
    return function (k) {
        return k+n;
    }
}

var inc_19 = create_incrementer(19);
var inc_17 = create_incrementer(17);
console.log(inc_19(23));  // 42
console.log(inc_17(23));  // 40
"use strict";

function create_counter(start, step) {
    var n;
    return function () {
        if (n === undefined) {
            n = start;
            return n;
        }
        n += step;
        return n;
    }
}

var count_by_3 = create_counter(1, 3);
var count_by_7 = create_counter(2, 7);

console.log(count_by_3());  // 1
console.log(count_by_3());  // 4
console.log(count_by_3());  // 7
console.log(count_by_7());  // 2
console.log(count_by_7());  // 9
console.log(count_by_7());  // 16
console.log(count_by_3());  // 10
console.log(count_by_7());  // 23

Exception handling

  • try
  • catch
function add(x, y) {
    if (Number(x) !== x) {
        throw {
            'name': 'TypeError',
            'message': 'First argument is not a number'
        };
    }
    if (Number(y) !== y) {
        throw {
            'name': 'AnyNameCanComeHere',
            'message': 'Second argument is not a number'
        };
    }
    return x+y;
}

var arr = [
    [2, 3],
    ['two', 3],
    [2, 'three'],
    [7, 9]
];
var i, res;
for (i=0; i<arr.length; i++) {
    v = arr[i];
    console.log(v);
    try {
        res = add(v[0], v[1]);
    } catch(e) {
        console.log('exception:', e);

    }
    console.log(res);
}

NodeJS: command line arguments

  • argv
console.log(process.argv);
console.log('--------------');
var i;
for (i = 0; i < process.argv.length; i++) {
    console.log(process.argv[i]);
}
$ node examples/js/nodejs_argv.js foo bar
[ 'node',
  '/Users/gabor/work/training/javascript/examples/js/nodejs_argv.js',
  'foo',
  'bar' ]
--------------
node
/Users/gabor/work/training/javascript/examples/js/nodejs_argv.js
foo
bar

NodeJS: prompt on STDIN

  • prompt
npm install prompt
var prompt = require('prompt');

prompt.start();

prompt.get(['fname', 'lname'], function (err, result) {
    var fname = result.fname;
    var lname = result.lname;
    console.log('Command-line input received:');
    console.log('  fname: ' + fname);
    console.log('  lname: ' + lname);
    prompt.get(['email'], function (err, result) {
        var email = result.email;
        console.log('Internal:');
        console.log('  fname: ' + fname);
        console.log('  lname: ' + lname);
        console.log('  email: ' + email);
    });
});

Transliterate

Work in progress...

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">

  <title>Transliterate</title>
</head>
<body>

Latin letters: <textarea id="latin" rows="10" cols="50"></textarea>

<button id="go">Guess</button>

<div id="result"></div>

<script src="transliterate.js"></script>

</body>
</html>
"use strict";

var hidden = Math.round(Math.random()*200+0.5);
console.log(hidden);

// ramat chaim => 'חיים רמת'

// 'ch' : 'ח'
var tr = {
    a: 'א',
    b: 'ב',
    c: '',
    d: 'ד',
    e: '',
    f: 'פ',
    g: 'ג',
    h: '',
    i: 'י',
    j: '',
    k: '',
    l: 'ל',
    m: 'מ',
    n: 'נ',
    o: 'ו',
    p: '',
    q: '',
    r: 'ר',
    s: 'ש',
    t: 'ת',
    ' ': ' '
}

function transliterate() {
    var latin = document.getElementById('latin').value;
    var result = '';
    var i;
    for (i = 0; i < latin.length; i++) {
        console.log(latin[i]);
        if (tr[ latin[i]] ) {
            result += tr[ latin[i]];
        }
    }
    document.getElementById('result').innerHTML = result;
    return false;
}

document.getElementById('latin').addEventListener('keyup', transliterate);

RegExp - Regular Expressions in JavaScript

RexExp Object

<script>
var text = 'There is a number 42 in this an another number #123 but nothing else.';
console.log(text);

// var p = new RegExp('\\d+');
// var p = new RegExp(/\d+/);
var p = /\d+/;
console.log(p);
var match = p.exec(text);
if (match) {
   console.log(match);
   console.log(match[0]);
   console.log(match['index']);
   console.log(match['input']);
}
</script>

Match

<script>
var text = 'There is a number 42 in this an another number #123 but nothing else.';
console.log(text);

var pattern = /\d+/;
var match = pattern.exec(text);
if (match) {
    console.log(match[0]);
}

var m = /\d+/.exec(text);
if (m) {
    console.log(m[0]);
}
</script>

Substitute

  • replace
  • /g

Replace the first match of a regex by a string. Replace it globally.

<script>
var text = 'There is a number 42 in this an another number #123 but nothing else.';
console.log(text);

var changed = text.replace(/\d+/, 'NUMBER');
console.log(changed);
console.log(text); 

var ch2 = text.replace(/\d+/g, 'NUMBER');
console.log(ch2);

</script>

RegExp cheat sheet

var pattern = new RegExp(pattern, modifiers);

. - match any character (except newline)

Character classes

  • [abcde] - match a single character: a, b, c, d, or e
  • [^abcde] - match a single character, except of a, b, c, d, and e
  • [a-e] - the same as [abcde]
  • \d - a single digit (the same as [0-9])
  • \w - a single word characer (the same as [a-zA-Z0-9_]
  • \s - a single white space
  • \D - a single non-digit (the same as [^\d])

Alternation

  • apple|banana

Grouping

()

Quantifiers

  • ? - 0 or 1
      • 1 or more
      • 0 or more (any number)
  • {n, m} - between n and m times (inclusive)

Modifiers

  • i - case insensitive
  • g - global
  • m - multiline

DOM - Document Object Model

Inject content in HTML

  • getElementById
  • innerHTML
<div id="display"></div>

<script src="inject_content.js"></script>

"use strict";

document.getElementById('display').innerHTML = 'Hello World';

Add event listener

  • addEventListener
<button id="btn">Click me</button>

<div id="display"></div>

<script src="add_event_listener.js"></script>

"use strict";

function clicked() {
    document.getElementById('display').innerHTML = 'Hello World';
}

document.getElementById('btn').addEventListener('click', clicked);

Get value of input box

<input id="data" size="30">
<button id="btn">Click me</button>
<div id="display"></div>

<script src="get_value_of_input_box.js"></script>
"use strict";

function clicked() {
    var input_value = document.getElementById('data').value;
    document.getElementById('display').innerHTML = input_value;
}

document.getElementById('btn').addEventListener('click', clicked);;

Get value of selected option

  • selectedIndex
  • getElementById
  • addEventListener
  • click
<select id="id_of_select">
<option></option>
<option value="2">two</option>
<option value="3">three</option>
<option value="4">four</option>
</select>

<button id="btn">Show selected</button>

<div id="display"></div>

<script src="get_selected_option.js"></script>
"use strict";

function show_selected() {
    var selector = document.getElementById('id_of_select');
    var value = selector[selector.selectedIndex].value;

    document.getElementById('display').innerHTML = value;
}

document.getElementById('btn').addEventListener('click', show_selected);;

Update selection box based on other selection

<html>
<head><title>Update form</title>
<script src="update_form.js" type="text/javascript"></script>
</head>
<body onload="fill_continents()">
<form method="POST" name="reg">
<select name="continent" onchange="change_continent()">
  <option></option>
</select>
<br />

<select name="country" >
<option><option>
</select>
<br />

<input type="button" value="Next" onclick="submit_form()">
</form>

</body>
</html>
"use strict";

var continents = new Array();
continents['na'] = "North America";
continents['sa'] = "South America";
continents['eu'] = "Europe";

var countries = new Array();
countries['na'] = new Array();
countries['sa'] = new Array();
countries['eu'] = new Array();
countries['na']['usa'] = "USA";
countries['na']['ca']  = "Canada";
countries['eu']['de']  = "Germany";
countries['eu']['at']  = "Austria";
countries['sa']['ch']  = "Chile";

function fill_continents() {
    document.reg.continent.length=1;
    document.reg.continent[0].value = "";
    document.reg.continent[0].text = "";
    for (c in continents) {
        var i = document.reg.continent.length++;
        document.reg.continent[i].value = c;
        document.reg.continent[i].text = continents[c];
    }

}
function change_continent() {
    var continent = document.reg.continent.value;
    document.reg.country.length=1;
    document.reg.country[0].value = "";
    document.reg.country[0].text = "";
    for (c in countries[continent]) {
        var i = document.reg.country.length++;
        document.reg.country[i].value = c;
        document.reg.country[i].text = countries[continent][c];
    }
}


function countries() {
   for(i=0; i<countries.length; i++) {
     alert(countries[i]);
   }
}


function submit_form() {
   //alert(reg.continent.value);
   countries();

   //alert(countries["us"]);
   //alert("done");
}

Autoresizing Grid

<div id="loc"></div>

<style>
table {
    width: 100%;
}
td {
  border: solid 1px;
}
/*td:first-child {
    background-color: red;
}*/
</style>

<script src="grid.js">
var resizer;
function create_table(n) {
    var html = '<table>';
    var needFirst = true;
    for (var j = 0; j < 2; j++) {
      html += '<tr>'
      //if (needFirst) {
	  //  	html += '<td rowspan="2">full</td>';
      //      needFirst = false;
      //}
      for (var i=0; i<n; i++) {
         html += '<td>' + j + ' ' + i + '</td>';
      }
      html += '</tr>';
    }
    html += '</table>';
    //console.log(html);

    document.getElementById('loc').innerHTML = html;
}

function resize_table() {
    console.log(window.innerWidth);
    console.log(window.innerHeight);

    var trs = document.getElementsByTagName('tr');
    for (var t=0; t < trs.length; t++) {
        console.log(t);
        trs[t].children[0].setAttribute("style", "width: " + ( 130 / n ) + '%');
        //trs[t].children[0].setAttribute("style", "background-color: red");

    }
}

function resize_table_later() {
    if (resizer == null) {
        resizer = new Date;
        setTimeout(resize_table_later, 1000);
        return;
    }
    if (Math.abs(new Date() - resizer) > 950) {
        resizer = null;
        console.log('resize');
    }
}

var n = 4;
create_table(n);
resize_table()
//window.addEventListener('resize', resize_table_later);


</script>

Local storage - counter

Local storage - counter - reload the page several times

<script>
console.log('Start');

var n = localStorage.getItem('counter');
if (n === null) {
    n = 0;
} else {
    n++;
}
console.log(n);
localStorage.setItem("counter", n);

console.log('End');
</script>

Remove item from local storage - reset counter

Remove item from Local storage - reset counter

<script>
console.log('Start');

var before = localStorage.getItem('counter');
console.log(before);

localStorage.removeItem('counter');

var after = localStorage.getItem('counter');
console.log(after);


console.log('End');
</script>

Clear local storage

Remove all the data from the local storage

localStorage.clear();

Local storage - boolean

  • JSON

In many browsers local storage can only store string. So when we store the boolean true or false, it actually stores the strings "true" or "false". In order to get back the real boolean values, we can use the JSON.parse() method.

Local storage - store boolean

<script>
console.log('Start');

var cond = localStorage.getItem('cond');
if (cond === null) {
    console.log('was null setting to false');
    cond = false;
} else {
    cond = JSON.parse(cond)
}

console.log(cond);
cond = ! cond;
console.log(cond);
localStorage.setItem("cond", cond);

console.log('End');
</script>

Other

Date

<div id="date"></div>
<div id="time"></div>

<script>
function set_time() {
    const now = new Date();
    const dt = document.getElementById("date");
    dt.innerHTML = now.toLocaleDateString("ISO", {
              year: '2-digit',
              month: '2-digit',
          });

}
set_time();

</script>

Try Catch

<input type="number" id="a">
<input type="number" id="b">
<button id="calc">Divide</button>
<div id="result"></div>

<script>

// Apparently dividing by 0 is not an exception in JavaScript
// So I have stupid other 

function calc() {
    console.log('calc');
    const res = div(document.getElementById('a').value, document.getElementById('b').value);
    console.log(res);
    document.getElementById('result').innerHTML = res;
}

function div(a, b) {
    console.log(`div(${a},${b})`);
    try {
        const c = a / b;
        if (c == 0) {
            handle_zero();
        }
        return c;
    } catch(error) {
        console.log(`Eception: ${error}`);
    }
}
document.getElementById('calc').addEventListener('click', calc);

</script>

Application

Install NodeJS

  • NodeJS (There is 18.16.0 LTS and Installing 20.3.0 Current)

  • Create a folder for the application, eg. examples/demo-app

  • Open CMD , cd to the folder of the application cd examples/demo-app

  • Create project npm init -y (The -y will make it use the defaults withot prompting for answers)

  • Install webpack by running npm install --save-dev webpack webpack-cli

  • These will install it in the node_modules folder and it will also create the files package.json and package-lock.json

Edit the package.json and add

  "scripts": {
    "build": "webpack --mode development",
    "watch": "webpack --mode development --watch"
  }

Then running

npm run build

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Getting Started</title>
  </head>
  <body>
    <script src="./main.js"></script>
  </body>
</html>
import add from './mymath';

console.log("hello world");
console.log(add(2, 8));
export default function add(x, y) {
	return x + y;
}
{
  "name": "demo-app",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --mode development",
    "watch": "webpack --mode development --watch"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.86.0",
    "webpack-cli": "^5.1.4"
  }
}

JavaScript Appendix

Resources

JavaScript Videos

Other

JavaScript Tools

  • JSLint Find common coding problems in JavaScript
  • JSLint Errors a site to explain the errors of JSLint and to give suggestions how to fix them.

Reserved words in JavaScript

abstract boolean break byte case catch char class const continue debugger default delete do double else enum export extends false final finally float for function goto if implements import in instanceof int interface long native new null package private protected public return short static super switch synchronized this throw throws transient true try typeof var volatile void while with

Awful parts

Based on Appendix A of "JavaScript: The Good Parts"

  1. Global variables - (window.fname = 'Foo'; fname = 'Foo'; var fname = 'Foo';), declare variables using 'var' inside functions
  2. Scope only functions create local scope. Declare variable at the top of the functions.
  3. Semicolon insertion.
  4. Reserved words. var case = 23; SyntaxError: missing variable name
  5. Unicode: JavaScript characters are 16 bit (either UCS-2 or UTF-16. Most of them use UTF-16)
  6. typeof returning 'object' for null and array as well. typeof /a/ can be either 'object' or 'function' depending on browser.
  7. parseInt (leading 0 might make the number base-8 in some browsers. User radix to ensure base)
    • can (numeric) add or concatenate strings. It works as 'add' only if both operands are numbers.
  8. Floating point - is not perfect representation. Use integers.
  9. NaN - NaN === NaN // false; NaN !== NaN // true; isNaN()
  10. Phony Arrays
  11. Falsy values
  12. hasOwnProperty is not truely reliable as it is a method that can be replaced.
  13. Objects are never truly empty like a hash in Perl or a dictionary in Python.
<script>
function foo() {
    return
    {
        status: true
    };
}

function bar() {
    return {
        status: true
    };
}

var f = foo();
console.log(f); // undefined
var b = bar();
console.log(b); // Object { status: true }
</script>
<script>
var o1 = { name: 'Foo Bar' };
var o2 = { case: 'FB'}
console.log(o1);
console.log(o2);
console.log(o1.name);
console.log(o2.case);
// var case = 23;  // SyntaxError: missing variable name
</script>
<script>

function is_object(thing) {
    if (thing && typeof thing === 'object' && thing.constructor !== Array) {
        return true; // thing is an object or an array!
    } else {
        return false;
    }
}

console.log(is_object(null));  // false
console.log(is_object([]));    // false
console.log(is_object({}));    // true

</script>
<script>

function is_array(thing) {
    if (thing && typeof thing === 'object' && thing.constructor === Array) {
        return true; // thing is an object or an array!
    } else {
        return false;
    }
}

console.log(is_array(null));  // false
console.log(is_array([]));    // true
console.log(is_array({}));    // false

</script>
<script>
console.log(parseInt("16"));             // 16
console.log(parseInt("16 little men"));  // 16  (no indication of imperfect parse)

console.log(parseInt("011"));  // 11
console.log(parseInt("08"));   // 8
console.log(parseInt("09"));   // 9

console.log(parseInt("011", 8));   // 9
console.log(parseInt("09", 10));   // 9
</script>

Bad Parts

Based on Appendix B of "JavaScript: The Good Parts"

  1. == and != are bad. Always use === and !==
  2. with statement - avoid it
  3. eval - can be dangerous. Don't use it.
  4. continue - Douglas Crockford recommends to avoid it as you can write code without it.
  5. switch - Always break. Don't let it fall through.
  6. Block-less statement - always use {} after 'if'.
  7. ++ -- - Douglas Crockford recommends to avoid them. I think there are places where they can be used without problems.
  8. Bitwise operators - usually there is no need for them in JavaScript.
  9. Function statement vs Function expressions
  10. Typed Wrappers - avoid new Boolean, new Number, new String, new Array, new Object
  11. new - name constructor functions with leading capital letter, or even better: avoid using 'new'.
  12. void - avoid it
function add(x, y) {
    ...
}
add = function (x, y) {
    ...
};

A good way to enforce that everything is private is to wrap the whole code in an anonymous function expression, and execute it upon parsing it.

(function() {
    ...
    // No new global variables
})();

The official ECMAScript grammar states, that if the first word is 'function' then it is part of a function statement, but this is a function expression. That why we add a pair of () around the function.

JSLint

Based on Appendix C of "JavaScript: The Good Parts"

  1. Declare all the variables using 'var'. Use /*global to declare what can be global.
  2. Members - JSLint will list all the used members.
  3. Options to JSLint
  4. Semicolons
  5. Line Breaking
  6. Comma - don't use it as operator
  7. Required Blocks
  8. Expression Statements
  9. for x in y - object.hasOwnProperty
  10. switch
  11. var
  12. with
  13. ...

Deep copy

  • JSON
"use strict";

var cases = [
    undefined,
    null,
    42,
    "some string",
    /some reg/,
    ['a', 'b'],
    [
        ['Foo', 23],
        ['Bar', 17]
    ],
    { a: [ 'b', 'c'] }
];
var j;


var deep_copy = function(o) {
    var i;

    if (o === undefined || o === null || typeof o === 'number' || typeof o === 'string' || o instanceof RegExp) {
        return o;
    }
    if (typeof o === 'object') {
        if (Array.isArray(o)) {
            var n = [];
            for (i = 0; i < o.length; i++) {
                n.push(deep_copy(o[i]));
            }
            return n;
        }
    }
    var n = {};
    var keys = Object.keys(o);
    for (i = 0; i < keys.length; i++) {
        n[ keys[i] ] = deep_copy(o[ keys[i] ]);
    }
    return n;
}


for (j = 0; j < cases.length; j++) {
    console.log(j);
    var dc = deep_copy(cases[j]);
    console.log(cases[j]);
    console.log(dc);
    //console.log(dc === cases[j]);
}

Invocation patterns

  • this

  • Method invocation (this is bound to the object)

  • Function invocation (this is bound to the global object)

  • Constructor invocation

  • Apply invocation (this is bound to what we passed to it)

Apply

  • apply
var f = function() {
    console.log(this);
}

var x = { fname: 'Gabor'};

f.apply(x, [2, 3]);

getElementsByClassName

  • getElementsByClassName
var buttons = document.getElementsByClassName('remove');
for (var i=0; i < buttons.length; i++) {
    buttons[i].addEventListener('click', remove);
};