Javascript
Introduction to Web Programming
by Dr. David Rodenas
david-rodenas.com
twitter.com/drpicox
github.com/drpicox
for Java and C# programmers
© 2017
History (I)
2
Self Scheme
(apply + '(1 2 3 4 5 6))
===> 21
(set! f (lambda (n) (+ n 100)))
(map f '(1 2 3))
===> (101 102 103)
Mocha
History (II)
3
Self Scheme
Mocha
History (III)
4
Self Scheme
Mocha
Livescript
History (IV)
5
Self Scheme
Mocha
Livescript
Javascript
Java
History (IV)
6
Self Scheme Java
Javascript
ECMAScript
Compatibility (I)
7
ECMAScript
ECMAScript 1
ECMAScript 2
ECMAScript 3
ECMAScript 4
ECMAScript 5
- default
- strict
ECMAScript 2015
ECMAScript 2016
ECMAScript 2017
https://github.com/tc39/proposals
Compatibility (II)
8
http://kangax.github.io/compat-table/es6/
Compatibility (III)
9
http://caniuse.com/
Compatibility (IV)
10
https://developer.mozilla.org
Good parts
11
https://www.infoq.com/presentations/efficient-programming-language-es6
Be Careful
let value = getSomeValue();
if (value !== value) {
alert('Value is not equal to itself');
}
// is there the alert possible?
12
Javascript
Javascript Types
• Everything is an Object
• Number: 1, 2, 5, 5000,-10, 3.14, 1e2, 1e-2, Infinity, NaN
• String: 'hello','a','long word'
• Boolean: true, false
• Array: [1,2,3], ['hi','there'], [3,'times', true]
• Date: new Date('December 17, 1995 03:24:00'), Date.now()
• RegExp: /ab+c/g, new RegExp('ab+c','g')
• Function: function hello() { return world; }
• Object: any of above, {}, {hello: 'world'}
14
Javascript Types
• Everything is an Object, but
• null
• undefined
15
Number (immutable)
• IEEE-754: 1, 2, 5, 5000, -10, 3.14, 1e2, 1e-2, Infinity, NaN, …
• Methods: toFixed, toExponential, …
• Math: it has all methods and constants that Number should
have
• Cast to number:
• let number = Number(value);
• let number = parseInt(value, 10);
• let number = +value;
16
Number (immutable)
17
Test it: (1.)
String (immutable)
• Any UCS-2 chain: 'hello', 'a', 'long word', …
• Character is length 1 string
• 'e' === 'hello'[1]
• Properties/Methods: length, slice, trim, concat, split, indexOf,
…
• Cast to string:
• let string = String(value);
• let string = value.toString();
• let string = '' + value;
18
String (immutable)
let single = 'single comma string';
let double = "double comma string";
let template = `template with ${'inter' + "polation"}`;
19
String (immutable)
20
Test it: (2.)
Boolean (immutable)
• Just true / false
• Cast to boolean:
• let boolean = Boolean(value)
• let boolean = !!value
21
"Boolean" (immutable)
22
FALSY TRUTHY
false true
null []
undefined {}
"" "false"
0 "0"
NaN ...
Boolean
// Ternary expressions
cond ? aValue : bValue
true ? aValue : bValue
null ? aValue : bValue
cond && aValue || bValue
true && aValue || bValue
null && aValue || bValue
aValue || bValue
23
Boolean (immutable)
24
Test it: (3.)
Array
• [1,2,3], [42,'sense',{of: 'life'}], [], …
• Properties: length, push/pop, shift/unshift, slice, map/reduce/
every/some, indexOf…
• Mixed content:
• Allow contents of different type for each element, including other
arrays
• Dynamic length:
• array = ['a','b','c']; array[4] = 'e';
• array[3] === undefined
• array.length = 3
25
Array mutators
26
// As stack
let array = ['b','c','d'];
array.push('e');
let e = array.pop();
array.unshift('a');
let a = array.shift();
// As queue
array.push('e');
let b = array.shift();
array.unshift('a');
let e = array.pop();
// Insert
let array = ['a','c','d'];
array.splice(1, 0, 'b');
// Remove
let array = ['a','x','b','c'];
array.splice(1, 1);
// Sort
let array = ['c','a','b'];
array.sort();
// Reverse
let array = ['c','b','a'];
array.reverse();
Array non-mutators
// As functional array
let copy = array.slice();
let numbers = ['a','b',1,2,3,'c'].slice(2,5);
let moreNumbers = [1,2,3].concat([4,5]);
let odds = numbers.filer(n => n % 2);
let doubles = numbers.map(n => n * 2);
let sum = numbers.reduce((s,n) => s + n);
let allPositives = numbers.every(n => n >= 0);
let thereIsATwo = numbers.some(n => n == 2);
let firstBig = numbers.find(n => n >= 3);
let bigIndex = numbers.findIndex(n => n >= 3);
let indexOfTwo = numbers.indexOf(2);
// Spread destructuring
let copy = [...numbers];
let concat = [...numbers, 4, 5, ...[6, 7, 8]];
let [one,...tail] = numbers;
27
Array
28
Test it: (4.)
Objects
• Anything but undefined or null: 'hello', 3, {rule: 'world'}, …
• Properties: prototype, constructor, …
• Static Methods: assign, create, defineProperties, defineProperty, freeze,
getOwnPropertyDescriptor, getOwnPropertyNames,
getOwnPropertySymbols, getPrototypeOf, is, isExtensible, isFrozen,
isSealed, keys, preventExtensions, seal, setPrototypeOf,
• Methods: hasOwnProperty, isPrototypeOf, propertyIsEnumerable,
toLocaleString, toSource, toString, valueOf, …
• Built-in objects: Array, ArrayBuffer, Boolean, DataView, Date, Error,
EvalError, Float32Array, Float64Array, Function, Generator,
GeneratorFunction, Infinity, Int16Array, Int32Array, Int8Array, InternalError,
JSON, Map, Math, NaN, Number, Object, Promise, RangeError, Reflect,
RegExp, Set, String, Symbol, SyntaxError, TypeError, TypedArray,
URIError, Uint16Array, Uint32Arrray, Uint8Array, Uint8ClampedArray,
WeakMap, WeakSet, …
29
Objects
• JSON constructor is the most common one
• let car = { color: 'blue' };
• Are string key/any value maps:
• Get property: 

obj.propertyName

obj['propertyName']
• Set property: 

obj.propertyName = newValue

obj['propertyName'] = newValue
30
Object
// Object is a Map:
// pairs string-value (properties)
let object1 = {
property: 'anyValue',
};
let object2 = new Object();
object.property = 'anyValue';
let object3 = new Object();
object['prop' + 'erty'] = 'anyValue';
31
Object
// By default, you can set any property
object.property = 'anyValue';
// And you can get any value
let value = object.property;
console.assert(value === 'anyValue');
// even if not defined
let notDefined = object.notDefined;
console.assert(notDefined === undefined);
32
Be Careful
let car = {
color: 'blue'
};
let carOwners = {};
carOwners[car] = 'elon';
JSON.stringify(carOwners); // hint: car is not string
33
Objects
// Spread & destructuring (in standardisation)
let main = {peter: 'tyrion', lena: 'cersei'};
let others = {sean: 'eddard', jason: 'khal'};
let copy = {...main};
let addFields = {...main, emilia: 'daenerys'};
let composed = {...main, ...others};
let {peter, lena} = main;
let {peter, ...rest} = main;
// Computed keys
let main = {['peter']: 'tyrion'};
// shorthand property names
let peter = 'tyrion';
let main = { peter };
34
Object
35
Test it: (5.)
Functions
• Are Objects
• Like arrays, numbers, strings, ...
• You can assign to a variable, object property, passed as an
argument, returned as result...
• Do not use new Function('n', 'n * 2')
36
Functions
// Short notation
const incr = a => a + 1;
const incr = (a) => a + 1;
const incr = a => { return a + 1; };
const incr = (a) => { return a + 1; };
const sum = (a, b) => a + b;
const sum = (a, b) => { return a + b };
37
Functions
// Short notation in object definition
const incrementer = {
incr(a) {
return a + 1;
},
};
incrementer.incr(3); // 4
// Long notation: function definition
function incr(a) {
return a + 1;
}
// Long notation: function expression
const incr = function(a) {
return a + 1;
}
38
Functions
// Function arguments can missmatch
incr(1) // === incr(1, ignoreOtherArguments)
incr() // === incr(undefined)
// Variable arguments
const sum = (first, ...rest) => first + sum(...rest);
sum(1, 2, 3) === sum(...[1, 2, 3])
// Arguments may have default values
const add = (a, b = 1) => a + b;
add(3) === 4
39
Functions
// May return any kind of object
const cast(tony, pepper) => ({ tony, pepper });
// No return or empty return is undefined
const makeUndefined() => { return; };
// Be careful: semicolon is optional (ops undefined)
const makeThree() => {
return
1 + 1 + 1;
};
40
Functions
// High order functions
const reduce = (array, fn, zero) => {
if (array.length === 0) { return zero; }
return fn(
array[0],
reduce(array.slice(1), fn, zero),
);
};
const add = (a, b) => a + b;
const sum = (array) => reduce(array, add, 0);
41
Function
42
Test it: (6.)
Class
• Are new in ES2015
• They can be transpiled to any browser that supports
Object.create and Object.defineProperties
• It uses a notation similar to object short hand
• There are no private fields (yet)
43
Class
// have one single constructor
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
// new instances with new
const square = new Rectangle(5, 5);
// access to set/get like any object
square.width = square.width + 1;
square['height'] = square['height'] + 1;
44
Class
// have functions (no methods)
class Animal {
speak() {
return 'makes noise';
}
}
// has not method overloading
class Animal {
speak() {
return 'makes noise';
}
speak(predatorNear) { // avoid duplicates
return predatorNear ? 'is silent' : 'makes noise';
}
}
45
Class
// may have "methods"
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
// new instances with new
const square = new Rectangle(5, 5);
// access to set/get like any object
square.width = square.width + 1;
square['height'] = square['height'] + 1;
46
Class (this)
// use «this» to access private members
class Pet {
constructor(name) {
this.name;
}
getName() {
return this.name;
}
salute() {
return `Hi ${this.getName()}`;
}
speak() {
return 'makes noise';
}
}
47
Class (this)
// there is no method
const boby = new Pet('boby');
// only functions
const speak = boby.speak;
speak();
const getName = boby.getName;
getName();
const lucas = {
name: 'lucas',
getName
};
lucas.getName();
48
METHOD
giphy.com
Class
// use extends for inheritance
class Animal {
speak() {
return 'makes noise';
}
}
// add behaviour
class Cat extends Animal {
purr() { … }
}
// or redefine behaviour
class Lion extends Cat {
speak() { return 'roars'; }
}
49
Class
50
Test it: (7.)
Closures
• Functions inside functions can access to variables and
arguments of outer functions.
• Variables and arguments keep their existence after the outer
function is finished.
51
Closures
const makeMultiply = (times) => {
return (value) => times * value;
};
const triple = makeMultiply(3);
triple(3) // === 9
52
Closures
const makeCounter = (initial) => {
return () => {
const current = initial;
initial += 1;
return current;
};
};
const countGuests = makeCounter(1);
const countActors = makeCounter(1);
// countActors() ? countActors() ?
// countGuests() ? countActors() ? countGuests() ?
53
Closures
// The equivalent in old Java
public IntSupplier makeCounter(int initial) {
final AtomicInteger counter =
new AtomicInteger(initial);
return new IntSupplier() {
public int getAsInt() {
return counter.getAndIncrement();
}
};
}
54
Closures
55
Function Call 4
Return @address
Stack
Function Call 3
Return @address
Function Call 2
Return @address
Function Call 1
Return @address
Current
Stack Frame
Grow
Local Variables
Local Variables
Local Variables
Local Variables
Closures
56
Function Call 4
Return @address
Stack
Function Call 3
Return @address
Function Call 2
Return @address
Function Call 1
Return @address
Local Variables
Local Variables
Local Variables
Local Variables
Scopes
Global
Scope
Parent Scope
new
new
new
new
Closures
// Use as callbacks
const startClock = () => {
let count = 0;
let intervalId = setInterval(() => {
console.log(count += 1);
}, 1000);
return () => {
clearInterval(intervalId);
};
};
let stopClock = startClock();
// …wait few seconds…
stopClock();
57
Closures
// Use to create modules
let myObj = (() => {
let privateState = …;
const privateFunction = () => { … }
return {
publicMethodA: function() {
…do something with privateState…
},
publicMethodB: function() {
…do something with privateFunction…
},
…
};
}());
58
Closures
59
Test it: (8.)
Async/Await
• Javascript is asynchronous in its foundation.
• Traditionally it uses callbacks to handle asynchronicity: you
pass a function which is called when the operation is finished
with the resulting data as argument.
• ES2015 standarises: a kind of object for dependency inversion,
it allows you to call an operation before knowing which function
(or functions) handles the resulting data.
• ES2017 introduces async/await: promises were introduced in
the core, and functions can natively generate them and
consume them emulating a synchronized methods (but they
are not blocking and may be interleaved with other callbacks)
60
Async/Await
• There is only one thread
• no interferences
• no semaphores
• no deadlocks
• no quantum loss
• but also:
• no parallel processing
• no preemption (a callback may freeze the whole system)
61
Async/Await
// Event loop
while (true) {
const events = waitForEvents();
events.forEach(event => {
const callbacks = getEventCallbacks(event);
callbacks.forEach(callback => {
try {
callback(event);
} catch (e) { … }
});
});
}
62
Async/Await
// Traditional callback
setTimeout(() => {
console.log('5 seconds passed');
}, 5000);
const cb = () => console.log('5 seconds passed');
setTimeout(cb, 5000);
63
Async/Await
// Traditional callback
const button = document.getElementById('my-button');
button.addEventListener('click', (event) => {
console.log('my-button-clicked', event);
});
const req = new XMLHttpRequest();
req.onreadystatechange = () => {
if (req.readyState === 4 && req.status !== 200) {
console.log('loaded', req.responseText);
}
}
req.open("GET", "/api/fruits");
req.send(null);
64
Async/Await
// Traditional callback
const get = (url, cb) => {
const req = new XMLHttpRequest();
req.onreadystatechange = () => {
if (req.readyState === 4 && req.status !== 200) {
cb(req.responseText);
}
}
req.open("GET", url);
req.send(null);
};
get('/api/fruits', (response) => {
console.log('loaded', response);
});
65
Async/Await
// With Promises
const responsePromise = fetch('/api/fruits');
responsePromise.then((response) => {
console.log('loaded', response);
});
66
Async/Await
// Promises and chaining
const responsePromise = fetch('/api/fruits');
responsePromise.then((response) => {
console.log('loaded', response);
});
const bananaPromise =
responsePromise.then(response => {
return response.fruits.banana;
});
bananaPromise.then((banana) => {
minion.eat(banana);
});
67
Async/Await
// Promises creation
const delay = (ms) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms);
});
};
delay(5000).then(() => {
console.log('5 seconds passed');
});
68
Async/Await
// Promises creation
const failAfter = (ms) => {
return new Promise((resolve, reject) => {
setTimeout(reject, ms);
});
};
failAfter(5000).then(() => {
console.log('5 seconds passed');
}, () => {
console.log('it has failed');
});
69
Async/Await
// Async functions
const sayHelloDelayed = async (ms) => {
await delay(ms);
console.log('hello');
};
sayHelloDelayed(5000);
70
Async/Await
// Async functions
const sayHelloDelayed = async (ms) => {
await delay(ms);
console.log('hello');
};
console.log('this message prints before "hello"');
sayHelloDelayed(5000);
71
Async/Await
// Async functions
const sayHelloDelayed = async (ms) => {
await delay(ms);
console.log('hello');
};
console.log('this prints before "hello"');
sayHelloDelayed(5000);
console.log('this also prints before "hello"');
72
Async/Await
// Async functions
const sayHelloDelayed = async (ms) => {
await delay(ms);
console.log('hello');
};
console.log('this prints before "hello"');
const resultPromise = sayHelloDelayed(5000);
console.log('this also prints before "hello"');
73
Async/Await
// Async functions
const sayHelloDelayed = async (ms) => {
await delay(ms);
console.log('hello');
};
console.log('this prints before "hello"');
const resultPromise = sayHelloDelayed(5000);
console.log('this also prints before "hello"');
resultPromise.then(() => {
console.log('this prints after "hello"');
});
74
Async/Await
// Async functions
const sayHelloDelayed = async (ms) => {
await delay(ms);
console.log('hello');
};
(async () => {
console.log('this prints before "hello"');
const resultPromise = sayHelloDelayed(5000);
console.log('this also prints before "hello"');
resultPromise.then(() => {
console.log('this prints after "hello"');
});
})();
75
Async/Await
// Async functions
const sayHelloDelayed = async (ms) => {
await delay(ms);
console.log('hello');
};
(async () => {
console.log('this prints before "hello"');
const resultPromise = sayHelloDelayed(5000);
console.log('this also prints before "hello"');
await resultPromise;
console.log('this prints after "hello"');
})();
76
Async/Await
// Async functions
const sayHelloDelayed = async (ms) => {
await delay(ms);
console.log('hello');
};
(async () => {
console.log('this prints before "hello"');
await sayHelloDelayed(5000);
console.log('this prints after "hello"');
})();
77
Async/Await
// Async functions
(async () => {
try {
await failDelayed(5000);
} catch (e) {
console.log('failed after 5 seconds');
}
})();
78
Closures
79
Test it: (9.)
Import/Export
• Allows to link with other files and get and publish symbols
• Symbols can be named or default
• Two path import possibilities:
• paths beginning with package-name import from package
• relative paths (a.k.a. './…') import from file in the current directory
• It has fallbacks:
• it automatically appends .js .jsx or .json if not specified
• if destination is a folder it reads index.js[x]
80
Import/Export
import rule from "./rule";
import * as math from "math-tools";
import { sqrt } from "math-tools";
import { sqrt as sq } from "math-tools";
import { min, max } from "math-tools";
import { min, max as big, … } from "math-tools";
import defaultMember, { sqrt } from "math-tools";
import defaultMember, * as math from "math-tools";
import "math-tools";
81
Import/Export
export { sqrt, min, max };
export { squareRoot as sqrt, min, max };
export let sqrt, min, max;
export let min = (a,b) => a < b ? a : b;
export const min = (a,b) => a < b ? a : b;
export default expression;
export default function (…) { … }
export default async function (…) { … }
export default async class (…) { … }
export default function sqrt(…) { … }
export { sqrt as default, … };
export * from './other-file';
export { name1, name2, …, nameN } from './other-file';
export { import1 as name1, name2, …, nameN } from …;
82
Import/Export
83
https://rollupjs.org/repl
«Self» Inheritance
Object
• Java, C#, C++, … are class oriented
• Classes inherits from other Classes







• Javascript is instance oriented
• Objects (instances) inherits from other objects
85
car:
prototype is

mcQueen: raceCar:
prototype is

Car
instance of
mcQueen: RaceCar
inherits from
Object
• Javascript is “classless” but has inheritance
• Java, C# is class oriented
• Javascript is instance oriented
• Inheritance is performed through prototype
• Every object can become a prototype of other object
• Every object has another object as prototype
• The main prototype of almost all objects is Object.prototype
86
Object
// By default objects have a Object's prototype
let car1 = {
color: 'blue',
};
let car2 = Object.create(Object.prototype);
car.color = 'blue';
87
carX:
.color
Object.prototype:prototype is

Object
// Object.prototype
{
constructor: …,
hasOwnProperty: …,
toString: …,
…
}
88
Object
// But it can have no prototype
let prototypelessObject = Object.create(null);
// Object.getPrototypeOf(prototypelessObject) ?
// Object.getPrototypeOf(Object.prototype) ?
// Object.getPrototypeOf(Object) ?
89
prototypelessObject: nullprototype is

Object
// Objects can have any object as prototype
let car = {
color: 'blue',
};
let tesla = Object.create(car);
// car.color ?
// tesla.color ?
90
car:
.color
Object.prototype:tesla:
prototype is

has value fallback
prototype is

has value fallback
Object
// Objects inherits its prototype properties
let car = {
color: 'blue',
};
let tesla = Object.create(car);
tesla.brand = 'tesla';
// tesla.color ?
// tesla.brand ?
// Object.keys(tesla) ?
91
car:
.color
tesla:
.brand
Object
// Objects can overwrite prototype properties
let car = {
color: 'blue',
};
let ferrari = Object.create(car);
ferrari.color = 'red';
// car.color ?
// ferrari.color ?
92
car:
.color
ferrari:
.color
Be Careful
let car = {
color: 'red'
};
let parkingSpot = {
car: car,
};
let wolowitzParkingSpot = Object.create(parkingSpot);
wolowitzParkingSpot.car.color = 'gray';
// wolowitzParkingSpot.car.color ?
// car.color ?
93
car:
.color
parkingSpot:
.car
Object
class Object {
private Map<String,Object> properties;
private Object prototype;
public Object get(String key) {
if (properties.containsKey(key)) {
return properties.get(key);
} else if (prototype != null) {
return prototype.get(key);
} else {
return Undefined;
}
}
public void set(String key, Object value) {
properties.put(key, value);
}
}
94
Object
• In matter of speaking:
• Object.method.property are like Java/C# static members

ex: Object.create
• Object.prototype.property are like Java/C# instance members

ex: Object.prototype.isPrototypeOf
• Only properties, in matter of speaking:
• methods are properties whose value is a function
• members are properties whose value is not a function
• Object is a map, with an optional fallback map called prototype
95
Be Careful
let wordCount = {};
let word;
while (word = getSomeWord()) {
if (wordCount[word]) {
wordCount[word] ++;
} else {
wordCount[word] = 1;
}
}
// does it works? always?
96
«Self» Classes
Class
Object.getPrototypeOf(Function) ?
98
Class
Object.getPrototypeOf(Function) ?
typeof Function ?
99
Class
Object.getPrototypeOf(Function) === Function.prototype
typeof Function === 'function'
100
Class
Object.getPrototypeOf(Function) === Function.prototype
Object.getPrototypeOf(Object) ?
typeof Function === 'function'
typeof Function ?
101
Class
Object.getPrototypeOf(Function) === Function.prototype
Object.getPrototypeOf(Object) === Function.prototype
Object.getPrototypeOf(Number) === Function.prototype
typeof Function === 'function'
typeof Object === 'function'
typeof Number === 'function'
102
Class
Object.getPrototypeOf(Function) === Function.prototype
Object.getPrototypeOf(Object) === Function.prototype
Object.getPrototypeOf(Number) === Function.prototype
typeof Function === 'function'
typeof Object === 'function'
typeof Number === 'function'
…
// Functions are constructors!
new Number(3)
103
Class
function Animal() {
}
let animal = new Animal();
104
Animal.prototype:animal:
Class
function Animal(name) {
this.name = name;
}
let fievel = new Animal('fievel');
105
Animal.prototype:
fievel:
.name
Class
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(this.name + ' makes a noise');
};
let fievel = new Animal('fievel');
106
Animal.prototype:
.speak
fievel:
.name
Class
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(this.name + ' makes a noise');
};
let fievel = new Animal('fievel');
let tanya = new Animal('tanya');
107
Animal.prototype:
.speak
tanya:
.name
fievel:
.name
Class
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(this.name + ' makes a noise');
};
let fievel1 = new Animal('fievel');
let fievel2 = Object.create(Animal.prototype);
Animal.call(fievel2, 'fievel');
108
Class
function Animal(name) { this.name = name; }
Animal.prototype.speak = function() { … };
function Lion(name) {
Animal.call(this, name + ' the lion');
}
Lion.prototype = Object.create(Animal.prototype);
Lion.prototype.constructor = Lion;
Lion.prototype.speak = function() {
console.log(this.name + ' roars!');
};
109
Animal.prototype:
.speak
.constructor
Lion.prototype:
.speak
.constructor
Class
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise');
}
}
class Lion extends Animal {
constructor(name) {
super(name + ' the lion');
}
speak() {
console.log(this.name + ' roars');
}
}
110
Class
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(this.name + ' makes a noise');
}
class Lion extends Animal {
constructor(name) {
super(name + ' the lion');
}
speak() {
console.log(this.name + ' roars');
}
}
111
Everything is an Object
Everything is an object
const array = [1,2,3];
array.foo = 'bar';
const add = (a, b) => a + b;
add.foo = 'bar';
113

Introduction to web programming for java and c# programmers by @drpicox

  • 1.
    Javascript Introduction to WebProgramming by Dr. David Rodenas david-rodenas.com twitter.com/drpicox github.com/drpicox for Java and C# programmers © 2017
  • 2.
    History (I) 2 Self Scheme (apply+ '(1 2 3 4 5 6)) ===> 21 (set! f (lambda (n) (+ n 100))) (map f '(1 2 3)) ===> (101 102 103) Mocha
  • 3.
  • 4.
  • 5.
  • 6.
    History (IV) 6 Self SchemeJava Javascript ECMAScript
  • 7.
    Compatibility (I) 7 ECMAScript ECMAScript 1 ECMAScript2 ECMAScript 3 ECMAScript 4 ECMAScript 5 - default - strict ECMAScript 2015 ECMAScript 2016 ECMAScript 2017 https://github.com/tc39/proposals
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
    Be Careful let value= getSomeValue(); if (value !== value) { alert('Value is not equal to itself'); } // is there the alert possible? 12
  • 13.
  • 14.
    Javascript Types • Everythingis an Object • Number: 1, 2, 5, 5000,-10, 3.14, 1e2, 1e-2, Infinity, NaN • String: 'hello','a','long word' • Boolean: true, false • Array: [1,2,3], ['hi','there'], [3,'times', true] • Date: new Date('December 17, 1995 03:24:00'), Date.now() • RegExp: /ab+c/g, new RegExp('ab+c','g') • Function: function hello() { return world; } • Object: any of above, {}, {hello: 'world'} 14
  • 15.
    Javascript Types • Everythingis an Object, but • null • undefined 15
  • 16.
    Number (immutable) • IEEE-754:1, 2, 5, 5000, -10, 3.14, 1e2, 1e-2, Infinity, NaN, … • Methods: toFixed, toExponential, … • Math: it has all methods and constants that Number should have • Cast to number: • let number = Number(value); • let number = parseInt(value, 10); • let number = +value; 16
  • 17.
  • 18.
    String (immutable) • AnyUCS-2 chain: 'hello', 'a', 'long word', … • Character is length 1 string • 'e' === 'hello'[1] • Properties/Methods: length, slice, trim, concat, split, indexOf, … • Cast to string: • let string = String(value); • let string = value.toString(); • let string = '' + value; 18
  • 19.
    String (immutable) let single= 'single comma string'; let double = "double comma string"; let template = `template with ${'inter' + "polation"}`; 19
  • 20.
  • 21.
    Boolean (immutable) • Justtrue / false • Cast to boolean: • let boolean = Boolean(value) • let boolean = !!value 21
  • 22.
    "Boolean" (immutable) 22 FALSY TRUTHY falsetrue null [] undefined {} "" "false" 0 "0" NaN ...
  • 23.
    Boolean // Ternary expressions cond? aValue : bValue true ? aValue : bValue null ? aValue : bValue cond && aValue || bValue true && aValue || bValue null && aValue || bValue aValue || bValue 23
  • 24.
  • 25.
    Array • [1,2,3], [42,'sense',{of:'life'}], [], … • Properties: length, push/pop, shift/unshift, slice, map/reduce/ every/some, indexOf… • Mixed content: • Allow contents of different type for each element, including other arrays • Dynamic length: • array = ['a','b','c']; array[4] = 'e'; • array[3] === undefined • array.length = 3 25
  • 26.
    Array mutators 26 // Asstack let array = ['b','c','d']; array.push('e'); let e = array.pop(); array.unshift('a'); let a = array.shift(); // As queue array.push('e'); let b = array.shift(); array.unshift('a'); let e = array.pop(); // Insert let array = ['a','c','d']; array.splice(1, 0, 'b'); // Remove let array = ['a','x','b','c']; array.splice(1, 1); // Sort let array = ['c','a','b']; array.sort(); // Reverse let array = ['c','b','a']; array.reverse();
  • 27.
    Array non-mutators // Asfunctional array let copy = array.slice(); let numbers = ['a','b',1,2,3,'c'].slice(2,5); let moreNumbers = [1,2,3].concat([4,5]); let odds = numbers.filer(n => n % 2); let doubles = numbers.map(n => n * 2); let sum = numbers.reduce((s,n) => s + n); let allPositives = numbers.every(n => n >= 0); let thereIsATwo = numbers.some(n => n == 2); let firstBig = numbers.find(n => n >= 3); let bigIndex = numbers.findIndex(n => n >= 3); let indexOfTwo = numbers.indexOf(2); // Spread destructuring let copy = [...numbers]; let concat = [...numbers, 4, 5, ...[6, 7, 8]]; let [one,...tail] = numbers; 27
  • 28.
  • 29.
    Objects • Anything butundefined or null: 'hello', 3, {rule: 'world'}, … • Properties: prototype, constructor, … • Static Methods: assign, create, defineProperties, defineProperty, freeze, getOwnPropertyDescriptor, getOwnPropertyNames, getOwnPropertySymbols, getPrototypeOf, is, isExtensible, isFrozen, isSealed, keys, preventExtensions, seal, setPrototypeOf, • Methods: hasOwnProperty, isPrototypeOf, propertyIsEnumerable, toLocaleString, toSource, toString, valueOf, … • Built-in objects: Array, ArrayBuffer, Boolean, DataView, Date, Error, EvalError, Float32Array, Float64Array, Function, Generator, GeneratorFunction, Infinity, Int16Array, Int32Array, Int8Array, InternalError, JSON, Map, Math, NaN, Number, Object, Promise, RangeError, Reflect, RegExp, Set, String, Symbol, SyntaxError, TypeError, TypedArray, URIError, Uint16Array, Uint32Arrray, Uint8Array, Uint8ClampedArray, WeakMap, WeakSet, … 29
  • 30.
    Objects • JSON constructoris the most common one • let car = { color: 'blue' }; • Are string key/any value maps: • Get property: 
 obj.propertyName
 obj['propertyName'] • Set property: 
 obj.propertyName = newValue
 obj['propertyName'] = newValue 30
  • 31.
    Object // Object isa Map: // pairs string-value (properties) let object1 = { property: 'anyValue', }; let object2 = new Object(); object.property = 'anyValue'; let object3 = new Object(); object['prop' + 'erty'] = 'anyValue'; 31
  • 32.
    Object // By default,you can set any property object.property = 'anyValue'; // And you can get any value let value = object.property; console.assert(value === 'anyValue'); // even if not defined let notDefined = object.notDefined; console.assert(notDefined === undefined); 32
  • 33.
    Be Careful let car= { color: 'blue' }; let carOwners = {}; carOwners[car] = 'elon'; JSON.stringify(carOwners); // hint: car is not string 33
  • 34.
    Objects // Spread &destructuring (in standardisation) let main = {peter: 'tyrion', lena: 'cersei'}; let others = {sean: 'eddard', jason: 'khal'}; let copy = {...main}; let addFields = {...main, emilia: 'daenerys'}; let composed = {...main, ...others}; let {peter, lena} = main; let {peter, ...rest} = main; // Computed keys let main = {['peter']: 'tyrion'}; // shorthand property names let peter = 'tyrion'; let main = { peter }; 34
  • 35.
  • 36.
    Functions • Are Objects •Like arrays, numbers, strings, ... • You can assign to a variable, object property, passed as an argument, returned as result... • Do not use new Function('n', 'n * 2') 36
  • 37.
    Functions // Short notation constincr = a => a + 1; const incr = (a) => a + 1; const incr = a => { return a + 1; }; const incr = (a) => { return a + 1; }; const sum = (a, b) => a + b; const sum = (a, b) => { return a + b }; 37
  • 38.
    Functions // Short notationin object definition const incrementer = { incr(a) { return a + 1; }, }; incrementer.incr(3); // 4 // Long notation: function definition function incr(a) { return a + 1; } // Long notation: function expression const incr = function(a) { return a + 1; } 38
  • 39.
    Functions // Function argumentscan missmatch incr(1) // === incr(1, ignoreOtherArguments) incr() // === incr(undefined) // Variable arguments const sum = (first, ...rest) => first + sum(...rest); sum(1, 2, 3) === sum(...[1, 2, 3]) // Arguments may have default values const add = (a, b = 1) => a + b; add(3) === 4 39
  • 40.
    Functions // May returnany kind of object const cast(tony, pepper) => ({ tony, pepper }); // No return or empty return is undefined const makeUndefined() => { return; }; // Be careful: semicolon is optional (ops undefined) const makeThree() => { return 1 + 1 + 1; }; 40
  • 41.
    Functions // High orderfunctions const reduce = (array, fn, zero) => { if (array.length === 0) { return zero; } return fn( array[0], reduce(array.slice(1), fn, zero), ); }; const add = (a, b) => a + b; const sum = (array) => reduce(array, add, 0); 41
  • 42.
  • 43.
    Class • Are newin ES2015 • They can be transpiled to any browser that supports Object.create and Object.defineProperties • It uses a notation similar to object short hand • There are no private fields (yet) 43
  • 44.
    Class // have onesingle constructor class Rectangle { constructor(height, width) { this.height = height; this.width = width; } } // new instances with new const square = new Rectangle(5, 5); // access to set/get like any object square.width = square.width + 1; square['height'] = square['height'] + 1; 44
  • 45.
    Class // have functions(no methods) class Animal { speak() { return 'makes noise'; } } // has not method overloading class Animal { speak() { return 'makes noise'; } speak(predatorNear) { // avoid duplicates return predatorNear ? 'is silent' : 'makes noise'; } } 45
  • 46.
    Class // may have"methods" class Rectangle { constructor(height, width) { this.height = height; this.width = width; } } // new instances with new const square = new Rectangle(5, 5); // access to set/get like any object square.width = square.width + 1; square['height'] = square['height'] + 1; 46
  • 47.
    Class (this) // use«this» to access private members class Pet { constructor(name) { this.name; } getName() { return this.name; } salute() { return `Hi ${this.getName()}`; } speak() { return 'makes noise'; } } 47
  • 48.
    Class (this) // thereis no method const boby = new Pet('boby'); // only functions const speak = boby.speak; speak(); const getName = boby.getName; getName(); const lucas = { name: 'lucas', getName }; lucas.getName(); 48 METHOD giphy.com
  • 49.
    Class // use extendsfor inheritance class Animal { speak() { return 'makes noise'; } } // add behaviour class Cat extends Animal { purr() { … } } // or redefine behaviour class Lion extends Cat { speak() { return 'roars'; } } 49
  • 50.
  • 51.
    Closures • Functions insidefunctions can access to variables and arguments of outer functions. • Variables and arguments keep their existence after the outer function is finished. 51
  • 52.
    Closures const makeMultiply =(times) => { return (value) => times * value; }; const triple = makeMultiply(3); triple(3) // === 9 52
  • 53.
    Closures const makeCounter =(initial) => { return () => { const current = initial; initial += 1; return current; }; }; const countGuests = makeCounter(1); const countActors = makeCounter(1); // countActors() ? countActors() ? // countGuests() ? countActors() ? countGuests() ? 53
  • 54.
    Closures // The equivalentin old Java public IntSupplier makeCounter(int initial) { final AtomicInteger counter = new AtomicInteger(initial); return new IntSupplier() { public int getAsInt() { return counter.getAndIncrement(); } }; } 54
  • 55.
    Closures 55 Function Call 4 Return@address Stack Function Call 3 Return @address Function Call 2 Return @address Function Call 1 Return @address Current Stack Frame Grow Local Variables Local Variables Local Variables Local Variables
  • 56.
    Closures 56 Function Call 4 Return@address Stack Function Call 3 Return @address Function Call 2 Return @address Function Call 1 Return @address Local Variables Local Variables Local Variables Local Variables Scopes Global Scope Parent Scope new new new new
  • 57.
    Closures // Use ascallbacks const startClock = () => { let count = 0; let intervalId = setInterval(() => { console.log(count += 1); }, 1000); return () => { clearInterval(intervalId); }; }; let stopClock = startClock(); // …wait few seconds… stopClock(); 57
  • 58.
    Closures // Use tocreate modules let myObj = (() => { let privateState = …; const privateFunction = () => { … } return { publicMethodA: function() { …do something with privateState… }, publicMethodB: function() { …do something with privateFunction… }, … }; }()); 58
  • 59.
  • 60.
    Async/Await • Javascript isasynchronous in its foundation. • Traditionally it uses callbacks to handle asynchronicity: you pass a function which is called when the operation is finished with the resulting data as argument. • ES2015 standarises: a kind of object for dependency inversion, it allows you to call an operation before knowing which function (or functions) handles the resulting data. • ES2017 introduces async/await: promises were introduced in the core, and functions can natively generate them and consume them emulating a synchronized methods (but they are not blocking and may be interleaved with other callbacks) 60
  • 61.
    Async/Await • There isonly one thread • no interferences • no semaphores • no deadlocks • no quantum loss • but also: • no parallel processing • no preemption (a callback may freeze the whole system) 61
  • 62.
    Async/Await // Event loop while(true) { const events = waitForEvents(); events.forEach(event => { const callbacks = getEventCallbacks(event); callbacks.forEach(callback => { try { callback(event); } catch (e) { … } }); }); } 62
  • 63.
    Async/Await // Traditional callback setTimeout(()=> { console.log('5 seconds passed'); }, 5000); const cb = () => console.log('5 seconds passed'); setTimeout(cb, 5000); 63
  • 64.
    Async/Await // Traditional callback constbutton = document.getElementById('my-button'); button.addEventListener('click', (event) => { console.log('my-button-clicked', event); }); const req = new XMLHttpRequest(); req.onreadystatechange = () => { if (req.readyState === 4 && req.status !== 200) { console.log('loaded', req.responseText); } } req.open("GET", "/api/fruits"); req.send(null); 64
  • 65.
    Async/Await // Traditional callback constget = (url, cb) => { const req = new XMLHttpRequest(); req.onreadystatechange = () => { if (req.readyState === 4 && req.status !== 200) { cb(req.responseText); } } req.open("GET", url); req.send(null); }; get('/api/fruits', (response) => { console.log('loaded', response); }); 65
  • 66.
    Async/Await // With Promises constresponsePromise = fetch('/api/fruits'); responsePromise.then((response) => { console.log('loaded', response); }); 66
  • 67.
    Async/Await // Promises andchaining const responsePromise = fetch('/api/fruits'); responsePromise.then((response) => { console.log('loaded', response); }); const bananaPromise = responsePromise.then(response => { return response.fruits.banana; }); bananaPromise.then((banana) => { minion.eat(banana); }); 67
  • 68.
    Async/Await // Promises creation constdelay = (ms) => { return new Promise((resolve, reject) => { setTimeout(resolve, ms); }); }; delay(5000).then(() => { console.log('5 seconds passed'); }); 68
  • 69.
    Async/Await // Promises creation constfailAfter = (ms) => { return new Promise((resolve, reject) => { setTimeout(reject, ms); }); }; failAfter(5000).then(() => { console.log('5 seconds passed'); }, () => { console.log('it has failed'); }); 69
  • 70.
    Async/Await // Async functions constsayHelloDelayed = async (ms) => { await delay(ms); console.log('hello'); }; sayHelloDelayed(5000); 70
  • 71.
    Async/Await // Async functions constsayHelloDelayed = async (ms) => { await delay(ms); console.log('hello'); }; console.log('this message prints before "hello"'); sayHelloDelayed(5000); 71
  • 72.
    Async/Await // Async functions constsayHelloDelayed = async (ms) => { await delay(ms); console.log('hello'); }; console.log('this prints before "hello"'); sayHelloDelayed(5000); console.log('this also prints before "hello"'); 72
  • 73.
    Async/Await // Async functions constsayHelloDelayed = async (ms) => { await delay(ms); console.log('hello'); }; console.log('this prints before "hello"'); const resultPromise = sayHelloDelayed(5000); console.log('this also prints before "hello"'); 73
  • 74.
    Async/Await // Async functions constsayHelloDelayed = async (ms) => { await delay(ms); console.log('hello'); }; console.log('this prints before "hello"'); const resultPromise = sayHelloDelayed(5000); console.log('this also prints before "hello"'); resultPromise.then(() => { console.log('this prints after "hello"'); }); 74
  • 75.
    Async/Await // Async functions constsayHelloDelayed = async (ms) => { await delay(ms); console.log('hello'); }; (async () => { console.log('this prints before "hello"'); const resultPromise = sayHelloDelayed(5000); console.log('this also prints before "hello"'); resultPromise.then(() => { console.log('this prints after "hello"'); }); })(); 75
  • 76.
    Async/Await // Async functions constsayHelloDelayed = async (ms) => { await delay(ms); console.log('hello'); }; (async () => { console.log('this prints before "hello"'); const resultPromise = sayHelloDelayed(5000); console.log('this also prints before "hello"'); await resultPromise; console.log('this prints after "hello"'); })(); 76
  • 77.
    Async/Await // Async functions constsayHelloDelayed = async (ms) => { await delay(ms); console.log('hello'); }; (async () => { console.log('this prints before "hello"'); await sayHelloDelayed(5000); console.log('this prints after "hello"'); })(); 77
  • 78.
    Async/Await // Async functions (async() => { try { await failDelayed(5000); } catch (e) { console.log('failed after 5 seconds'); } })(); 78
  • 79.
  • 80.
    Import/Export • Allows tolink with other files and get and publish symbols • Symbols can be named or default • Two path import possibilities: • paths beginning with package-name import from package • relative paths (a.k.a. './…') import from file in the current directory • It has fallbacks: • it automatically appends .js .jsx or .json if not specified • if destination is a folder it reads index.js[x] 80
  • 81.
    Import/Export import rule from"./rule"; import * as math from "math-tools"; import { sqrt } from "math-tools"; import { sqrt as sq } from "math-tools"; import { min, max } from "math-tools"; import { min, max as big, … } from "math-tools"; import defaultMember, { sqrt } from "math-tools"; import defaultMember, * as math from "math-tools"; import "math-tools"; 81
  • 82.
    Import/Export export { sqrt,min, max }; export { squareRoot as sqrt, min, max }; export let sqrt, min, max; export let min = (a,b) => a < b ? a : b; export const min = (a,b) => a < b ? a : b; export default expression; export default function (…) { … } export default async function (…) { … } export default async class (…) { … } export default function sqrt(…) { … } export { sqrt as default, … }; export * from './other-file'; export { name1, name2, …, nameN } from './other-file'; export { import1 as name1, name2, …, nameN } from …; 82
  • 83.
  • 84.
  • 85.
    Object • Java, C#,C++, … are class oriented • Classes inherits from other Classes
 
 
 
 • Javascript is instance oriented • Objects (instances) inherits from other objects 85 car: prototype is
 mcQueen: raceCar: prototype is
 Car instance of mcQueen: RaceCar inherits from
  • 86.
    Object • Javascript is“classless” but has inheritance • Java, C# is class oriented • Javascript is instance oriented • Inheritance is performed through prototype • Every object can become a prototype of other object • Every object has another object as prototype • The main prototype of almost all objects is Object.prototype 86
  • 87.
    Object // By defaultobjects have a Object's prototype let car1 = { color: 'blue', }; let car2 = Object.create(Object.prototype); car.color = 'blue'; 87 carX: .color Object.prototype:prototype is

  • 88.
  • 89.
    Object // But itcan have no prototype let prototypelessObject = Object.create(null); // Object.getPrototypeOf(prototypelessObject) ? // Object.getPrototypeOf(Object.prototype) ? // Object.getPrototypeOf(Object) ? 89 prototypelessObject: nullprototype is

  • 90.
    Object // Objects canhave any object as prototype let car = { color: 'blue', }; let tesla = Object.create(car); // car.color ? // tesla.color ? 90 car: .color Object.prototype:tesla: prototype is
 has value fallback prototype is
 has value fallback
  • 91.
    Object // Objects inheritsits prototype properties let car = { color: 'blue', }; let tesla = Object.create(car); tesla.brand = 'tesla'; // tesla.color ? // tesla.brand ? // Object.keys(tesla) ? 91 car: .color tesla: .brand
  • 92.
    Object // Objects canoverwrite prototype properties let car = { color: 'blue', }; let ferrari = Object.create(car); ferrari.color = 'red'; // car.color ? // ferrari.color ? 92 car: .color ferrari: .color
  • 93.
    Be Careful let car= { color: 'red' }; let parkingSpot = { car: car, }; let wolowitzParkingSpot = Object.create(parkingSpot); wolowitzParkingSpot.car.color = 'gray'; // wolowitzParkingSpot.car.color ? // car.color ? 93 car: .color parkingSpot: .car
  • 94.
    Object class Object { privateMap<String,Object> properties; private Object prototype; public Object get(String key) { if (properties.containsKey(key)) { return properties.get(key); } else if (prototype != null) { return prototype.get(key); } else { return Undefined; } } public void set(String key, Object value) { properties.put(key, value); } } 94
  • 95.
    Object • In matterof speaking: • Object.method.property are like Java/C# static members
 ex: Object.create • Object.prototype.property are like Java/C# instance members
 ex: Object.prototype.isPrototypeOf • Only properties, in matter of speaking: • methods are properties whose value is a function • members are properties whose value is not a function • Object is a map, with an optional fallback map called prototype 95
  • 96.
    Be Careful let wordCount= {}; let word; while (word = getSomeWord()) { if (wordCount[word]) { wordCount[word] ++; } else { wordCount[word] = 1; } } // does it works? always? 96
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
    Class Object.getPrototypeOf(Function) === Function.prototype Object.getPrototypeOf(Object)=== Function.prototype Object.getPrototypeOf(Number) === Function.prototype typeof Function === 'function' typeof Object === 'function' typeof Number === 'function' 102
  • 103.
    Class Object.getPrototypeOf(Function) === Function.prototype Object.getPrototypeOf(Object)=== Function.prototype Object.getPrototypeOf(Number) === Function.prototype typeof Function === 'function' typeof Object === 'function' typeof Number === 'function' … // Functions are constructors! new Number(3) 103
  • 104.
    Class function Animal() { } letanimal = new Animal(); 104 Animal.prototype:animal:
  • 105.
    Class function Animal(name) { this.name= name; } let fievel = new Animal('fievel'); 105 Animal.prototype: fievel: .name
  • 106.
    Class function Animal(name) { this.name= name; } Animal.prototype.speak = function() { console.log(this.name + ' makes a noise'); }; let fievel = new Animal('fievel'); 106 Animal.prototype: .speak fievel: .name
  • 107.
    Class function Animal(name) { this.name= name; } Animal.prototype.speak = function() { console.log(this.name + ' makes a noise'); }; let fievel = new Animal('fievel'); let tanya = new Animal('tanya'); 107 Animal.prototype: .speak tanya: .name fievel: .name
  • 108.
    Class function Animal(name) { this.name= name; } Animal.prototype.speak = function() { console.log(this.name + ' makes a noise'); }; let fievel1 = new Animal('fievel'); let fievel2 = Object.create(Animal.prototype); Animal.call(fievel2, 'fievel'); 108
  • 109.
    Class function Animal(name) {this.name = name; } Animal.prototype.speak = function() { … }; function Lion(name) { Animal.call(this, name + ' the lion'); } Lion.prototype = Object.create(Animal.prototype); Lion.prototype.constructor = Lion; Lion.prototype.speak = function() { console.log(this.name + ' roars!'); }; 109 Animal.prototype: .speak .constructor Lion.prototype: .speak .constructor
  • 110.
    Class class Animal { constructor(name){ this.name = name; } speak() { console.log(this.name + ' makes a noise'); } } class Lion extends Animal { constructor(name) { super(name + ' the lion'); } speak() { console.log(this.name + ' roars'); } } 110
  • 111.
    Class function Animal(name) { this.name= name; } Animal.prototype.speak = function() { console.log(this.name + ' makes a noise'); } class Lion extends Animal { constructor(name) { super(name + ' the lion'); } speak() { console.log(this.name + ' roars'); } } 111
  • 112.
  • 113.
    Everything is anobject const array = [1,2,3]; array.foo = 'bar'; const add = (a, b) => a + b; add.foo = 'bar'; 113