SEASON-5
SEASON-5
JavaScript Fundamentals
1.2
What is JavaScript?
High-level, dynamic, weakly typed, prototype-based, multi-paradigm, and
interpreted programming language
...but more importantly...
JavaScript
High-level, dynamic, weakly typed, prototype-based, multi-paradigm, and
interpreted programming language
It is deployed as source code and it is an essential part of the Web platform
ECMAScript
International standard that defines JavaScript
Developed by Technical Committee 39 (TC-39)
Issued as Ecma-262 and ISO/IEC 16262
JavaScript Engines
1.5
Ubiquitous JavaScript
Client Side
Server Side
Mobile
Desktop
Database
Web APIs
1.8
JS Fu*k
It is possible to write any JavaScript code with only 6 chars
1 . 11
{ Exercise }
Development Environment Setup
Google Chrome
Node.js
2.1
Introduction to JavaScript
Many people start writing JavaScript
without taking the time to learn the language...
... but when you need to know what you are doing!
2.2
Data Types
2.3
{ Add-On }
Objects
A JavaScript object can be looked at as a simple collection of Properties
Objects implement a Map Data Structure, where properties are containers that hold primitives or other objects
obj.a; // 42
obj.b; // true
obj['c']; // {}
Property Access
Objects can have properties read or written to, as well as new ones
added or removed dynamically
// 1. Dot syntax
newObject.someKey = "Hello"; // create a new property if non existent and update value
var value = newObject.someKey; // get property value
// 4. delete property
delete newObject.someKey;
2.7
References
Variables can hold the actual values of primitives types or references to objects
console.log(a.n); // 80
console.log(b.n); // 80
a.n = 100;
console.log(a.n); // 100
console.log(b.n); // 100
2.8
Dynamic Typing
The type of a variable does not have to be declared and can be
reassigned to a different type
var bootcamp = 10; // bootcamp is a Number
bootcamp = 'Lisbon'; // bootcamp is now a String
bootcamp = true; // bootcamp is now a Boolean
bootcamp = { edition: 10, city: 'Lisbon', running: true }; // bootcamp is now an Object
Type Coercion
Converting a value from one type to another is called casting when done
explicitly, and coercion when done implicitly
Type Coercion in JavaScript can be magical...
... but also evil, confusing and sometimes a really bad idea!
2 . 10
Function Declarations
In JavaScript, functions are ordinary objects with the
additional capability of being callable
function foo() {
return 42; function foo(a) {
} console.log(a + 1, arguments);
return 2;
function baz() {} }
The typeof operator doesn't always returns the type No checking is done on either the type or the number
of arguments passed into a function
A function that returns nothing is equivalent to The variable arguments is an array like object
returning undefined containing all passed arguments into the function
All argument passing is done by value, you can pass-
by-value a primitive or a reference to an object
2 . 11
Function Arguments
The arguments object is a local variable available within all
functions
Contains a numerical property for each argument passed to the function
function myFunction(x, y) {
console.log(x);
console.log(y);
console.log(arguments['0']);
console.log(arguments.0);
}
Primitive Wrappers
Primitives are immutable and have no methods, but JavaScript has the
Boolean, Number and String objects that wrap around primitive values
var str = 'this is a string primitive';
typeof str; // 'string'
Lexical Scope
JavaScript has support for static lexical scope only
Variable scope depends on its position on the source code
// a global definition of animal
var animal = 'Horse, ';
function mammal() {
mammal();
animal += ' a mammal with four legs';
// Dog or Horse?
console.log(animal);
Local Scope
Local variables exist only within the function body
of which they are defined
console.log(dog); // bad things will happen
function animal() {
Please note that contrary to other programming languages, ES5 local scope is bound to function and not block!
3.4
Global Scope
Global variables live through the entire execution of the runtime
and can be accessed and altered in any scope
var dog = 'Dog'; // global definition of dog
function animals() {
function badAnimal() {
Variables defined outside a function or without the var keyword will be bound to the Global Scope
ES5 contains a strict mode, causing the interpreter to check and scream at evil things such as implicit globals
3.5
Global Objects
Contrary to other programming languages, JavaScript does not have a
standard library, but it does come with a few built in objects available
var date2 = new Date('December 17, 2017 03:24:00');
var date 1 = new Date.now(); // time in milliseconds since the UNIX epoch
Hoisting
Variable declarations are always processed before any code is executed
Function Expressions
Functions can be used before they are declared
due to function declaration hoisting
foo(); // prints bar to the console
function foo() {
console.log('bar');
}
IIFE
A function expression can be invoked immediately,
many times useful to avoid global scope pollution
// This function will execute immediately
// extra parentheses are required to tell the interpreter
// this is a function expression and not a declaration
(function() {
var name = 'sting';
})();
Arrays
Powerful high-level list-like objects, containing
methods to perform traversal and mutation operations
// array literal syntax is built in the language
var arr = [ 'hello world', 42, true, { a: 1 } ];
arr[999] = null;
arr.length; // 1000
typeof arr[10]; // 'undefined'
Neither the length of an array nor the types of its elements are fixed
5.2
stack.pop(); // 3 queue.shift(); // 1
stack.pop(); // 2 queue.shift(); // 2
stack.pop(); // 1 queue.shift(); // 3
stack.pop(); // undefined queue.shift(); // undefined
shift and unshift also work pop and unshift also work
Array Operations
An array can be populated ...and a String generated
with contents from a String... from the elements of an Array
var sentence = 'JavaScript is a lot of fun!'; var numbers = [1, 9, 7, 4];
var words = sentence.split(' '); var year = numbers.join();
Array Iteration
var words = ['JavaScript', 'Bootcamp', 'Fun', 'Games'];
Object.keys(obj).forEach(function(key) {
console.log('Value of key ' + key + ' is ' + obj[key]);
});
5.5
// apply a transform function to an array, transforming each element in the array into its square root
var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt); // [1, 2, 3]
// reduce an array to one single value, the total number of characters in the array
var animals = ['cat', 'dog', 'fish'];
var letters = animals.reduce(function(sum, word) {
return sum + word.length;
}, 0); // 10
// most array functions can be chained together, this example flattens an array and finds even numbers
const data = [[1,2,3], [4,5,6], [7,8,9]];
const evens = data.reduce(function(total, value) {
return total.concat(value);
}, []).filter(function(value) {
return value % 2 === 0;
});
The original array objects are not mutated by map, filter or reduce
6
{ Exercise }
✓ you should get a green check mark on all tests
1.1
JavaScript
Frontend Web
Development
1.2
Modern Web
The modern Web brought us a plethora of new technologies, such as:
CSS to describe the appearance or presentation of content on a webpage
JavaScript, the programming language that runs in the browser and can add interactivity and other dynamic features to
web applications
Web APIs, used to perform a variety of tasks, such as manipulating the DOM, playing audio or video, or generating 3D
graphics
AJAX, used to fetch data from a server without having to do a full page refresh
WebRTC, enabling audio/video streaming and data sharing between browser clients
2.1
It is an object oriented representation of the web page and can be modified with JavaScript
2.3
DOM Tree
In the DOM, documents assume a tree structure of nodes
Browsers use layout engines such as
Webkit (Safari), Blink (Chrome) or Gecko
(Firefox) to parse HTML into a DOM and
render it on screen
The window.onload method receives as argument a function callback to be invoked when the document is loaded into the
browser window. The DOM may not fully populated before that!
2.5
DOM Objects
In the DOM API, each HTML element is represented by an object
Each object has various properties and methods that correspond to the
appearance or behavior of the corresponding HTML element
Element Attributes
Most HTML attributes of an element can be accessed through the object
property of the same name
var elem = document.getElementById("logo_image");
console.log("The URL of this image is: " + elem.src);
Element Contents
Element contents can be retrieved or changed
element.innerHTML - This property represents the HTML within the element
element.textContent - This property represents the plain text within the element. This is equivalent to the inner HTML,
but with all the tags stripped out
{ Exercise }
Head to www.google.com and apply some creative CSS and
content to the logo and sign-in button
2 . 12
Events
The DOM provides methods for registering and
unregistering event listeners on elements
EventTarget is an interface implemented by DOM nodes that can receive
events and may have listeners for them
element.addEventListener(type, callback, options) - Register an event handler of a specific event type on the EventTarget
element.removeEventListener(type, listener, options) - Removes an event listener from the EventTarget
element.dispatchEvent(event) - Dispatch an event to this EventTarget
Clicking on a form submission button will cause the browser to submit the form to the server by default
The event listener can choose to prevent the action from being run
2 . 14
Event Propagation
When an event is fired, the element’s event handlers are first fired.
The element’s parent’s event handlers are fired next.
That element’s parent’s event handlers are also fired, and so on, until the
dom root element ( document) is reached
When an event handler is fired, it has an opportunity to stop the event from propagating to its parent. To do so, the
handler can call event.stopPropagation() method on the event object
2 . 15
{ Exercise }
List Customer data using the DOM API
var customerData = [
{"id":1,"firstName":"Rui","lastName":"Ferrão","email":"[email protected]","phone":"777888"},
{"id":2,"firstName":"Sergio","lastName":"Gouveia","email":"[email protected]","phone":"777999"},
{"id":3,"firstName":"Bruno","lastName":"Ferreira","email":"[email protected]","phone":"777666"},
{"id":4,"firstName":"Rodolfo","lastName":"Matos","email":"[email protected]","phone":"777333"}
];
3.1
AJAX
3.2
AJAX
Asynchronous JavaScript and XML refers to a technique for creating
better, faster and more interactive client-side web applications
JavaScript for interacting with the browser
and responding to events
The DOM for accessing and manipulating
the structure of the HTML page
XML, which represents the data exchanged
between the server and client
An XMLHttpRequest object for
asynchronously exchanging data between
the client and the server
Not a technology in itself, AJAX refers to
a variety of technologies coming together
3.3
XMLHttpRequest
The XMLHttpRequest object provides the API to make AJAX requests,
using a variety of formats within a JavaScript application.
var ajax;
if (window.XMLHttpRequest) {
// Mozilla, Safari, IE7+ ...
ajax = new XMLHttpRequest();
} else if (window.ActiveXObject) {
// IE 6 and older
ajax = new ActiveXObject('Microsoft.XMLHTTP');
}
{ Exercise }
Fetch Customer data with AJAX
Load the customers from the JavaBank REST API
using the XMLHttpRequest object
1.1
1.2
jQuery 101
jQuery is a fast, small, and feature-rich JavaScript library.
It's designed to ease HTML DOM manipulation, event handling,
animation, and AJAX Http requests, with a simple API that works
across the various browsers.
1.3
jQuery Usage
Adding the jQuery library to an HTML page using a CDN:
<head>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js">
</script>
</head>
// create the new element and append it to every node with the given class name
$(element).appendTo('.className');
{ Exercise }
jQuery DOM manipulation
Substitute all DOM API manipulation on customer data exercise
with jQuery
1.6
{ Exercise }
AJAX with jQuery
Replace XMLHttpRequest with jQuery
2.1
{ Exercise }
jQuery CRUD
1.1
JavaScript Engines
Runtime engines consist of two main components:
Call Stack
All JavaScript code runs within the scope of
what is known as an Execution Context
A global execution context is created initially and pushed into the call stack
Every time a function is invoked a new execution context is created and pushed into the call stack
Every time a function returns its execution context is popped from the call stack
1.4
Stack Overflow
If the maximum call stack size is exceeded
the program terminates with a RangeError
function foo() {
foo(); // call foo recursively forever
}
foo();
1.5
Code Execution
While executing code, the runtime engine goes through two different
phases multiple times, until there is no more code to run
1. Creation Phase - A new Execution Context gets created
2. Execution Phase - During this phase, the following actions occur:
Created EC is stored in the call stack
Code from the EC is executed
EC is removed from the call stack
Code from the previous EC continues to execute
1.6
Execution Context
It is possible to conceptually represent each execution context (EC)
as an object with three properties
Activation Object stores all variables
defined within the current EC
Scope Chain gives access to the
Activation Object for all parent
lexical scopes
This Binding is a reference to the
object that owns the currently
executing code
1.7
Activation Object
When a function is activated (called), the interpreter scans the function
for arguments and local variables or local function declarations
function foo(x, y) {
var z = 30;
function bar() {}
foo(10, 20);
Scope Chain
Container of Activation Objects for the executing function lexical scope
function printOranges() {
console.log(oranges);
}
function printMoreOranges() {
var oranges = 11;
printOranges();
}
var obj1 = {
owner: "obj1",
getOwner: getOwner
};
var obj2 = {
owner: "obj2"
};
getOwner(); // "global"
obj1.getOwner(); // "obj1"
getOwner.call( obj2 ); // "obj2"
new getOwner(); // undefined
The value of this is dynamically bound depending on how the function was called!
1 . 10
this Pitfalls
The implicit this binding can produce strange results
// get a collection of all button elements on the page
var buttons = document.getElementsByTagName('button');
buttons[i].onclick = function() {
function disableButton() {
this.disabled = true;
}
Borrowing Methods
JavaScript makes it possible to use one object's method
on a totally different object
The arguments object looks like an array with numerical indexed keys, but lacks all of the array methods
// this blows up, the arguments object lacks the native array methods
function upperCaseArguments() {
return arguments.forEach(function(arg) {
return arg.toUpperCase();
});
}
return argsAsArray.map(function(arg) {
return arg.toUpperCase();
});
}
2.1
Closures
2.2
Closures
Accessing variables up the scope chain will make the interpreter
preserve the corresponding EC and create what is called a closure
Closures effectively enable JavaScript asynchronous programming style
addImgClickHandler();
function addImgClickHandler() {
var counter = 0;
var myImage = document.querySelector('img');
myImage.onclick = function() {
counter++;
console.log('You have clicked this image ' + counter + 'times');
}
}
By the time the user clicks the button, the execution of addImgClickHandler has long terminated,
but the counter variable is still accessible
2.3
Explicit Closures
Closures seem complex at first, but they are a powerful tool with many
practical use cases, allowing for creative, expressive and concise code
var twice = multiplier(2);
console.log(twice(5));
function multiplier(factor) {
return function(number) {
return number * factor;
};
}
The AO created upon the execution of multiplier is preserved and available during the execution of twice
2.4
Module Pattern
Closures can be utilized to emulate the concept of classes
with public and private members
var secretFactory = function(secret, key) {
var tries = 3;
return {
get: function(secretKey) {
tries -= 1;
return (tries > 0 && key === secretKey) ? secret : null;
}
};
};
console.log(secret1.get('1234')); // null
console.log(secret1.get()); // null
console.log(secret1.get('password')); // null
console.log(secret1.get(1234)); // null, secret has been destroyed
console.log(secret2.get('password')); // a message
2.5
Closure Pitfalls
Closures together with lexical scope can produce strange results
var funcs = [];
funcs[0](); // 3
funcs[1](); // 3
funcs[2](); // 3
Object Creation
and
Inheritance
3.2
Inheritance
Through inheritance an object gets access to properties and
methods of another object
Classical Inheritance - a class blueprint is required in
order to create an object
Prototypal Inheritance - an existing object can be
used as a prototype for other objects
Prototypal Inheritance
Based on a delegation mechanism in which
non existent properties are looked up in prototype objects
var funnyGuy = {
firstName: 'Pedro',
lastName: 'Antoninho'
};
console.log(funnyGuy);
console.log(funnyGuy.valueOf());
console.log(funnyGuy.__proto__.valueOf.call(funnyGuy));
Prototype Link
It is possible to create a new object that delegates to an existing one
var foo = {
a: 42
};
// shadowing foo.a
bar.a = 2; // hides foo.a
console.log(bar.a); // 2
console.log(foo.a); // 42
Shadowing occurs because properties are only looked up the prototype chain if not present on the object
3.5
Constructor Functions
A constructor function is used to create multiple instances of the
same type of objects, all delegating to a common prototype
function Shape(color, borderThickness) { // roughly the equivalent of performing
this.color = color; // var shape = new Shape('red', 2.0);
this.borderThickness = borderThickness;
} var shape = Object.create(Shape.prototype);
Shape.call(shape, 'red', 2.0);
var shape = new Shape('red', 2.0);
They emulate classes, should only be used with the new operator
and should be capitalized for readability
All functions come with a prototype property that:
references an object that delegates to Object.prototype
contains a constructor property that references the function itself
can be used to expose methods to all objects created from the constructor function
DO NOT confuse the prototype property of a function with the prototype of an object (__proto__)!
3.6
Pseudo-Classical Inheritance
Despite its prototypal nature, classical inheritance can be emulated in
Javascript with constructor functions and the new operator
// Constructor function for objects of type Shape
function Shape(color, borderThickness) {
// property initialization code inside constructor function
this.color = color;
this.borderThickness = borderThickness;
}
Subclassing
Subclassing can be achieved in pseudo-classical inheritance
by chaining and linking constructors together
// Animal Constructor
function Animal(name) {
this.name = name;
}
// Animal Methods
Animal.prototype.walk = function() {
console.log(this.name + ' is walking');
}
// Dog Constructor
function Dog(name, breed) {
// chain Animal and Dog constructors
Animal.call(this, name);
this.breed = breed;
}
// Make Dog inherit from Animal by overriding Dog prototype object
// with a new empty object that delegates to Animal.prototype
Dog.prototype = Object.create(Animal.prototype);
// Recreate constructor property destroyed in previous line
Dog.prototype.constructor = Dog;
// Dog Methods
Dog.prototype.bark = function() {
console.log(this.name +
' is from breed' + this.breed +
' and says rauf rauf');
}
4.1
Error Handling
4.2
Errors
When the JS engine encounters an erroneous situation, it's normal flow is
interrupted by doing what is known as throwing an error:
Early Errors - thrown during parsing, can not be handled
Runtime Errors - thrown during execution, can be handled by catching the error
Syntax errors normally occur early, but sometimes they can occur at runtime as well
var x = 2;
console.log(x); // prints the value 2
// this line will trigger a runtime syntax error
var y = new Function('console.log(x + 1;');
4.3
Error Handling
It is possible to mark a block of statements in the code and
specify a response if an error is thrown at runtime
try {
var myObject = {};
myObject.method(); // throws an error
} catch (err) {
console.log('An error has occurred: ', err);
} finally {
console.log('Error has been handled!');
}
4.4
Error Objects
JavaScript error handling is typically performed through the
generic Error constructor or one of it's subconstructors
try {
var myObject = {};
myObject.method(); // throws an error
} catch (err) {
console.log(typeof err); // object
console.log(err instanceof Error); // true
console.log(err instanceof TypeError); // true
// print a human readable description of the error
console.log(err.name + ': ' + err.message); // TypeError: myObject.method is not a function
if (debug) {
// dump the full stack trace to the console
console.log(err.stack);
}
}
4.5
Error Throwing
An error can be thrown to signal a
runtime error in the execution of the code
The execution of the current function will stop
and control passed to the first catch clause in the call stack
function doSomethingRisky() {
throw new Error('something went wrong...');
}
try {
doSomethingRisky();
} catch (err) {
console.log(err.name); // Error
console.log(err.message); // something went wrong
}
Custom Errors
The Error object can also be used as a base object for custom errors
function CustomError(message, module) {
// Error is not your typical constructor function
var error = Error(message); // chain CustomError and Error constructors
this.name = 'CustomError'; // the standard error name property
this.message = error.message; // the standard message property
this.stack = error.stack; // the stack trace
this.module = module; // the custom module property
}
// Make CustomError inherit from a new error object,
CustomError.prototype = Object.create(Error.prototype);
CustomError.prototype.constructor = CustomError;
try {
throw new CustomError('wrong credentials', 'authentication');
} catch(e){
console.log(e.name + ': ' + e.module + ' - ' + e.message);
console.log(e.stack);
}
Error does not require new and does not manipulate this, it simply returns a new Error instance
5
{ Exercise }
✓ you should get a green check mark on all tests
1
Asynchronous Programming
2.1
Concurrency
JavaScript is a single threaded, concurrent, non-blocking and
asynchronous programming language
2.2
Execution Environment
The JavaScript engine runs inside an execution environment
such as the Browser or Node.js
Concurrency Model
JavaScript has a concurrency model based on an event loop
This model is quite different from models in other languages like C and Java
where concurrency is achieved mainly via parallel code execution using threads
2.4
Event Queue
Browser APIs expose operations that can run concurrently
using a small number of threads
// to be called when data is available
function ajaxCallback() {
console.log(this.responseText);
}
// to be called every 10 ms
function timerCallback() {
console.log('tick');
}
setInterval(timerCallback, 10);
var ajax = new XMLHttpRequest();
ajax.addEventListener('load', ajaxCallback);
ajax.open('GET', 'https://api.github.com');
ajax.send();
Event Loop
When the Call Stack is empty, the Event Loop takes the first
callback from the Event Queue and places it at the top of the Call Stack
for execution
console.log('start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
console.log('end');
// start, end, setTimeout
Rendering Engine
Browsers rendering engine executes in the same thread
as the JavaScript runtime
Rendering events have higher priority for execution
and will be fetched from the queue first
// what happens if we run this?
while (true) {}
The event loop will not fetch anything from the queue
if the call stack is not empty
3.1
Callback Functions
A function is called a Callback when it is passed as an argument to
another function for later execution
Callbacks can be invoked synchronously or asynchronously:
// synchronous callback // asynchronous callback
function isOdd(num) { function ring() {
return num % 2; console.log('RING!');
} }
var numbers = [1, 5, 8, 19, 232, 456];
var oddNumbers = numbers.filter(isOdd); setInterval(ring, 1000);
All isOdd callback invocations end The invoking setInterval function ends before the ring
before the invoking filter function ends callback is invoked
3.2
I/O Handling
To handle I/O operations, two different API models exists:
Synchronous and Blocking I/O Asynchronous and Non-Blocking I/O
{ Hands On }
HTML Animation
3.4
JSON
JavaScript Object Notation is a lightweight data interchange format
It is based on a subset of JavaScript and widely used in web applications
to exchange data between the client and the server
// a plain js object
var obj = { ticker: 'AAPL', name: 'Apple Inc' };
Introducing JSON
3.5
fetchData(processResults);
function fetchData(cb) {
var ajax = new XMLHttpRequest();
ajax.addEventListener('load', cb);
ajax.open('GET', 'https://api.exchangeratesapi.io/latest');
ajax.send();
}
// asynchronous callback
function processResults(event) {
fetchData(processResults);
function fetchData(cb) {
$.ajax({
url: 'https://api.exchangeratesapi.io/latest',
type: 'GET',
dataType: 'json',
success: cb
});
}
// asynchronous callback
function processResults(results) {
var usd = results.rates.USD;
var container = $('#rate');
container.html('<p>1 EUR = ' + usd + ' USD</p>');
}
});
3.7
try {
fetchDataAsync(processResults);
} catch (error) {
// error handling logic
console.log('Caught Error: ', error);
}
function processResults(results) {
throw Error('something went wrong');
}
Application will blow up with Uncaught Error and fetchData call will not be present on stack trace
3.8
function fetchData(cb) {
$.ajax({
url: 'https://api.exchangeratesapi.io/latest',
type: 'GET',
dataType: 'json',
success: function(results) { cb(null, results) },
error: function(request, statusText, httpError) { cb(httpError || statusText) }
});
}
{ Exercise }
AJAX with Error Handling
4.1
Callback Woes
Two very important aspects of synchronous code
for function composition are:
1. They return values - feed the return value from one function straight into the next
2. They throw exceptions - if one function fails, all others in the chain are bypassed until error is handled
try {
} catch (error) {
// handle error
}
Callback Headaches
Callbacks in sequence are hard... In parallel they are harder...
Promises
An abstraction built on top of callbacks that gives us back
functional composition and error bubbling in the async world
A Promise object represents the eventual completion (or failure)
of an asynchronous operation and its resulting value
Easy in sequence... Equally as easy in parallel...
Creating Promises
A promise can be created using a constructor function,
after which it will be in one of the following states:
1. pending - initial state, neither fulfilled nor rejected
2. fulfilled - the operation completed successfully
3. rejected - the operation failed
var promise = new Promise(function(resolve, reject) {
} else {
}
});
The constructor receives an async function callback with methods for resolving or rejecting the promise
4.5
Using Promises
A promise is a an thenable object to which callbacks can be
attached
promise.then(function(result) {
}, function(err) {
Promise Chaining
Promises can be chained together to transform values or
run additional async actions one after another
var promise = doSomethingAsync();
promise
.then(doSomethingElseAsync)
.then(doSomethingElseAsync)
.then(doSomethingElseAsync, handleSpecificError)
.then(doSomethingElseAsync)
.then(doSomethingElseAsync)
.catch(handleGenericError)
.finally(alwaysRunThis);
Both specific and generic error handling callbacks can be attached to promises
4.7
Parallel Execution
Parallel promises fulfills when all of the promises have fulfilled or
rejects as soon as one of the promises rejects
var promise = Promise.all([
doSomethingAsync(),
doSomethingAsync(),
doSomethingAsync().catch(handleSpecificError,
doSomethingAsync(),
]).catch(handleGenericError);
Redundant Promises
It is possible to settle a promise as soon as one of many
promises settles
var promise = Promise.race([
doSomethingAsync(),
doSomethingAsync(),
doSomethingAsync().catch(handleSpecificError,
doSomethingAsync(),
]).catch(handleGenericError);
asyncThing1().then(function() {
return asyncThing2();
}).then(function() {
return asyncThing3();
}).catch(function(err) {
return asyncRecovery1();
}).then(function() {
return asyncThing4();
}, function(err) {
return asyncRecovery2();
}).catch(function(err) {
console.log("Don't worry about it");
}).then(function() {
console.log("All done!");
});
blue lines for promises that fulfill or red for ones that reject
4 . 10
Settled Promises
It is possible to create settled promises
without actually performing any async action
function doSomethingAsync() {
// make sure we always return a promise, even if no async code has been executed
doSomethingAsync().then(onSuccess).catch(onError);
Since a promise is always returned, we can use then and catch callback methods
on the promise return value, which will always be executed in the next event loop tick
4 . 11
{ Exercise }
AJAX with Promises
Use the browser fetchapi to order a list of GitHub users by score
https://developer.github.com/v3/search/
4 . 12
{ Exercise }
✓ you should get a green check mark on all tests
5.1
JavaScript Modules
A module is a reusable piece of code that encapsulates implementation
details and exposes public methods so it can be used by other code
Modules should allow us to:
abstract code
encapsulate code
code reuse
manage code dependencies
5.3
Modular JavaScript
Before ES6, no official syntax to define modules existed and developers
were often times forced to choose between:
code their entire application in a single file, which results in a big mess
expose on the global scope some variation of the module pattern
which often lead to namespace collisions
<!--
developers used to write a bunch of script tags with implicit dependencies that had to be
manually ordered and pray for no ordering issues or collisions on the global scope...
-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.min.js"></script>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<script src="https://www.google-analytics.com/analytics.js"></script>
<script src="js/main.js"></script>
<script src="js/module1.js"></script>
<script src="js/module2.js"></script>
<script src="js/module3.js"></script>
5.4
Module Systems
Various formats to define modules in JavaScript were developed,
minimizing the lack of native JavaScript module syntax
Some of the most widely adapted and well known formats are:
AMD - Asynchronous Module Definition, an asynchronous module system for the browser
CommonJS - Popular system used by Node, can be used in the browser with tools such as Browserify or Webpack
UMD - Universal Module Definition, supports both AMD and CommonJS modules, both in Node and the Browser
ES6 modules - native javascript modules, supported on newer browsers only
5.5
// Methods
function myFunc() {
// do something with jquery here...
};
RequireJS
JavaScript file and module loader supporting the AMD standard
A JavaScript application consisting of multiple modules and their
respective dependencies can be bootstraped with a single script tag:
<!DOCTYPE html>
<html>
<head>
<title>My Web App</title>
<!-- data-main attribute tells require.js to load the js/app.js file after require.js loads -->
<script data-main="js/app"
src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.5/require.min.js"></script>
</head>
<body>
<h1>My Web App</h1>
</body>
</html>
5.7
RequireJS Configuration
A global require object is exposed, which can be used to configure
RequireJS and bootstrap the application
// Filename: js/app.js
require.config({
// Filename: js/main.js
require(['router'], function(router) {
$(document).ready(function() {
console.log('dom is ready');
router.start();
});
});
5.8
Hash-based Routing
URLs can contain some data prepended with a # character
This data is called the hash fragment
Changes in the hash fragment never trigger a page reload and can be
used for storing the state of the client application
5 . 10
{ Hands On }
Simple JavaScript Router
5 . 11
{ Exercise }
MarvelApp
1.1
Modern JavaScript
1.2
ES6/ES2015
ES6 is not just a modest set of new APIs but a radical jump!
Constants Classes
Scoping Symbol Type
Arrow Functions Iterators
Extended Parameter Handling Generators
Template Literals Map/Set/WeakMap/WeakSet
Extended Literals Typed Arrays
Enhanced Regular Expression New Built-In Methods
Enhanced Object Properties Promises
Destructuring Assignment Meta-Programming
Modules Internationalization & Localization
Browser Support
ES6 support varies substantially
across browsers and JS environments
Node Support
ES6 and ES2016(ES7) are already mainstream on Node.js
console.log(a); // 2
console.log(a); // 2
No more reason to use function scope, block scoping is the way to go!
2.2
let
let declarations attach to the block scope
{
console.log(a); // undefined
var a = 1;
console.log(a); // 1
console.log(b); // ReferenceError thrown
block scoped variables are not initialized until they appear in the block
2.3
funcs[1](); // 1
funcs[3](); // 3
const
Read-only block scoped variable declaration
{
const a = 2;
console.log(a); // 2
a = 3; // TypeError!
}
... REST/SPREAD
When used as a function argument, it will gather the rest
of the arguments into an array
function foo(a, ...args) {
console.log(a); // 1
console.log(args); // [2,3,4,5]
}
foo(1, 2, 3, 4, 5);
When used in front of an array it will spread out into its individual values
function foo(a, b, c, d, e, f) {
console.log(a, b, c, d, e, f);
}
foo(...values); // 1 2 3 4 5
No more need to use the [].slice.call(arguments) hack to convert arguments into an array
3.2
console.log(foo(5, 6)); // 11
console.log(foo(5)); // 35
console.log(foo(0, 1)); // oops... what is the problem here?
// ES6 way
function bar(x = 10, y = 30) {
return x + y;
}
console.log(bar(5, 6)); // 11
console.log(bar(5)); // 35
console.log(bar(0, 1)); // 1
Destructuring Assignment
Unpacks selected values from arrays, or properties from objects,
into distinct variables
// ES5 style // ES6 style
var results, company, companyDetails; const [company, companyDetail] = Promise.all([
companyService.get(id),
results = Promise.all([ companyService.getDetail(id)
companyService.get(id), ]);
companyService.getDetail(id)
]);
company = results[0];
companyDetails = results[1];
Object Enhancements
A number of important convenience extensions
to the object literal exist in ES6
// ES5 // ES6
var color = 'red'; const color = 'red';
var speed = '10'; const speed = '10';
var computedProp = 'hand brake'; const computedProp = 'hand break';
firstName: 'Rui',
lastName: 'Ferrão',
get fullName() {
return this.firstName + ' ' + this.lastName;
},
set fullName(value) {
[this.firstName, this.lastName] = value.split(' ');
}
};
Template Literals
String templates provide interpolation,
giving us a lot more control over creating strings
// ES5 // ES6
var name = 'Pedro'; let name = 'Pedro';
var greeting = "Hello " + name + "!"; let greeting = `Hello ${name} !`;
A great benefit of interpolated string literals is they are allowed to span across multiple lines
The line breaks in the interpolated string literal are preserved in the string value
4.1
Arrow Functions
Shortcut for creating anonymous functions with
this bounded to lexical scope
// How can we fix this? // ES6
let person = { let person = {
name: 'Rui', name: 'Rui',
delayedHello(delay) { delayedHello(delay) {
setTimeout(function() { setTimeout(() => {
console.log(this.name); console.log(this.name);
}, delay); }, delay);
} }
}; };
Before ES6 we could solve this using bind to set the this context or grab the context on a closure ( that)
The arguments object is not available with arrow functions, the ...rest operator has to be used instead
4.2
Shorter Syntax
Arrow functions provide for a compact syntax
// ES5 // ES6
var math = { let math = {
product: function(x, y) { product: (x, y) => x * y,
return x * y; square: x => x * x
}, }
square: function(x) {
return x * x;
}
};
we got rid of function brackets and return statement for one liners,
as well as parentheses if the function receives only one argument
5.1
Classes
ES6 Classes are syntactic sugar over prototype-based inheritance
// ES5 // ES6
class Person {
// constructor function
function Person(name, age) { constructor(name, age) {
this.name = name; this.name = name;
this.age = age; this.age = age;
} }
Subclassing
extends keyword can be used to create a class as a child of another class
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
Default Constructors
A default constructor is created for all classes if omitted
class Animal {
};
super(...args);
Modules
ES6 introduced a new standardized module format
One module per file
Module API is static
Modules are singletons and mantain state
Importing a module implies a blocking load
Module Exports
The export keyword can be used in front of a declaration
or as an operator with a list of bindings to export
// all API members as named exports
Module Imports
The import keyword can be used to load a module from another one
// loads, compiles and evaluates the module without actually importing any of its bindings
import "module";
import only the specific bindings from a module that are required
6.4
// utils.js
export function addTextToBody(text) {
const div = document.createElement('div');
div.textContent = text;
document.body.appendChild(div);
}
type=module makes the browser treat the inline or external script as an ES6 module
7.1
Async/Await
Abstraction built on top of Promises/Generators that allows writing
asynchronous code in a readable and synchronous looking fashion
// With ES6 Promises // With ES2017 async/await
function fetchUser(login) { async function fetchUser(login) {
(async function() {
await sleep(1000); // wait for 1 second
console.log('Done!');
})();
Sequential Flows
Mutiple promises can be executed sequentially using the await operator
async function fetchGitHub(endpoint) {
console.log(`${user.name} repositories:`);
repos.forEach((repo) => console.log(repo.name));
}
Parallel Flows
The Promise.all method can be used to fire multiple promises in parallel
async function fetchGitHub(endpoint) {
console.log(`${user.name} repositories:`);
repos.forEach((repo) => console.log(repo.name));
}
Error Handling
Async functions return a rejected promise when an error is thrown
async function fetchGitHubUser(login) {
const api = `https://api.github.com/users/${login}`;
const response = await fetch(api);
const body = await response.json();
if (!response.ok) {
throw new Error(body.message); // throwing inside async rejects the returned promise
}
return body;
}
But things do not work quite as expected inside a forEach or other array methods...
console.log('Finished!');
7.7
{ Exercise }
AJAX with async/await
8
{ Exercise }
✓ you should get a green check mark on all tests
1
2.1
User Interfaces
Hard to build because there is so much state
Data changing over time is the root of all evil
2.3
What is React?
A Library for creating User Interfaces
Uses a Virtual DOM that selectively renders subtrees of nodes based
upon state changes
Renders UI and responds to events
People say it is the V in MVC...
I agree the Model is missing
And it is mostly about the View
But my Controller is somewhere in there!
2.4
Separation of Concerns
Design principle for separating a computer program into distinct sections, such that each
section addresses a separate concern
Most JavaScript MVC frameworks end up separating by technology and not by concerns!
View and Controllers are tightly coupled, making it difficult to change one without the changing the other
2.5
Separation of Components
React uses Components to separate concerns,
written with the full power of JavaScript.
Component Based
React is all about building components, not templates
They split the UI into independent reusable pieces
Components are reusable, composable, maintainable, testable and know how to render themselves into the DOM
2.7
Composition
Just like regular functions, React components can be composed together
This principle is a key feature of React and present at the core of how react applications are developed
2.8
Reacts declarative style leads to more readable code and with less bugs
2.9
Virtual DOM
Re-render on every state change seems expensive,
but is fast because it happens on a Virtual DOM.
On every update the following process takes place:
1. New virtual DOM subtree is built
2. Diff between new and old is performed
3. Minimal set of DOM mutations is calculated
4. DOM mutations are queued
5. All updates are executed together in a single batch
React Ecosystem
3.2
WebPack
Static module bundler for modern JavaScript applications
Recursively builds a dependency graph that includes every module in the
application and packages them into one or more bundles
3.4
Webpack Configuration
Webpack can be configured around four core concepts:
Entry point indicates which module webpack use to begin building its dependency graph
Output property tells webpack where to emit the bundles
Loaders enable webpack to convert to modules
and process all types of files
Plugins can be used to perform a wide variety of tasks such as optimization and minification
// webpack config uses common.js node modules, not ES6
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist') // absolute path required
},
{ Hands On }
Webpack Build System
3.6
{
// babel config in package.json file
"babel": { "presets": ["env", "react"] }
}
3.7
Axios
Promise based HTTP client for the browser and Node.js
Automatic JSON transforms
XSRF protection
Request canceling
async function getUser() {
try {
const response = await axios.get('/user?ID=12345');
console.log(response);
} catch (error) {
console.error(error);
}
}
React Basics
4.2
React Elements
Immutable object describing what should be rendered to the screen
and containing two main properties:
type - String for DOM node or ReactClass for a react component
props - element attributes
{ {
type: 'div', type: Button,
props: { props: {
className: 'container', className: 'ui primary button',
children: '<Academia de Código_>' children: 'Login'
} }
} }
React Components
A React Component is a function or a class
which accepts input properties and returns a React Element
// Button Component
function Button(props) {
return React.createElement('button', props);
}
React Components must act like pure functions with respect to their props and do not attempt to change them
4.4
{ Hands On }
Rendering React Components
4.5
JSX
Syntax extension to JavaScript to describe React Elements
Syntactic sugar for React.createElement(component, props, ...children)
Instead of artificially separating technologies by putting markup and logic in separate files,
React separates concerns with loosely coupled components that contain both
4.6
Inline Styles
The style attribute can be used to style a React component
An object with camelCased properties is used, not strings
// paragraph style object
const pStyle = {
color: 'red'
};
Inline styles are normally used for dynamic computed styles as CSS classes are generally more efficient
4.7
{ Hands On }
Rendering JSX Components
5.1
React Components
5.2
Functional Components
Contain no state and expressed as a single pure function which
accepts a props object and returns a React element
// Declare the React Welcome Component
function Welcome(props) {
return <h2>Welcome {props.name}</h2>;
}
// Same as above
const element = Welcome({name: 'Rui'});
ReactDOM.render(element, document.getElementById('root'));
Functional components are stateless and pure, for the same props they always return the same element
React components should start with uppercase ( <Welcome />) to distinguish them from regular DOM tags( <div /> )
5.3
Composing Components
Complex UI does not fit in a single function and needs to
be abstracted into reusable pieces, hiding implementation details
JSX makes it really easy to compose components together
function ListItem(props) {
return <li>{props.item}</li>;
}
function Popular() {
return (
<ul>
<ListItem item="JavaScript" />
<ListItem item="Java" />
<ListItem item="Ruby" />
</ul>
);
}
When a part of the UI is used several times or is complex enough on its own,
it should be extracted into a reusable component.
5.4
Compositional Components
Wrapper Components can be created using the children property
// usage: // usage:
<PrimaryButton <PrimaryButton>
icon={IconFile} text="Login" <IconFile/> Login
/> </PrimaryButton>
Property Typechecking
React includes a property typechecking library to help
catching bugs during development
import PropTypes from 'prop-types';
ListItem.propTypes = {
item: PropTypes.string.isRequired,
color: PropTypes.string
};
prop types and default values checks are enforced during development but removed from production code
5.6
Lists in React
We can create lists in React using JSX and
plain JavaScript array methods such as map or filter
function ListItem({ item }) {
return <li>{item}</li>;
}
function Popular() {
const languages = ['All', 'JavaScript', 'Java', 'HTML', 'CSS', 'C', 'C++'];
return (
<ul>
{ languages.map(lang => <ListItem key={lang} item={lang} />) }
</ul>
);
}
Array items require special unique key attribute for react to identify items changed, added or removed
Contrary to other JavaScript frameworks, there is no special syntax, its all JavaScript with JSX sugar on top
5.7
Class Components
A Class component can be created by extending from
React.Component
class Popular extends React.Component {
render() {
return (
<ul>
{ languages.map(lang => <ListItem key={lang} item={lang} />) }
</ul>
);
}
}
Component State
State allows React components to change their output over time
function ListItem({ item, color }) {
return <li style={{ color }}>{item}</li>;
}
selectLanguage(lang) {
this.setState({ selected: lang });
}
render() {
return (
<ul>
{Popular.languages.map(lang => {
let color = lang === this.state.selected ? 'red' : 'black';
return <ListItem color={color} key={lang} item={lang} />;
})}
</ul>
);
}
}
Component state lives in a special state property, explicitly updated by invoking the setState() method
Updating the state causes the component to re-render
5.9
Updating State
Updates to the UI are achieved through state updates,
which are enqueued, batched and delayed by React
class Counter extends React.Component {
state = { value: 0 };
// new state does not depend on previous state, shallow merge is performed
reset() {
this.setState({ value: 0}, this.stateUpdateCb);
}
render() {
return <h2>{this.state.value}</h2>;
}
}
State updates have to be explicitly triggered through setState(), it is not possible to update this.state directly
5 . 10
Event Handling
Event handlers receive instances of SyntheticEvent,
a cross-browser wrapper around the native events
class Counter extends React.Component {
state = { value: 0 };
increment = () => {
this.setState(
prevState => ({ value: prevState.value + 1 }),
this.stateUpdateCb
);
};
render() {
return <h2 onClick={this.increment}>{this.state.value}</h2>;
}
}
React events are named using camelCase and not lowercase like DOM events
SyntheticEvent is reused and all properties nullified for performance, making it unusable in asynchronous callbacks
5 . 11
{ Exercise }
Clickable React Counter
5 . 12
{ Exercise }
Popular Programming Languages Clickable Menu
6.1
Mounting Phase
Component is instantiated and inserted into the DOM
Updating
Component is being re-rendered due to changes in props or state
Component Re-render
When the rendering process finds a difference in a component
it re-renders the whole subtree
function NothingChanges() {
console.log('Will render one more time...');
return <h3>Nothing changed here...</h3>;
}
increment = () => {
this.setState(
prevState => ({ value: prevState.value + 1 })
);
};
render() {
return (
<div>
<h2 onClick={this.increment}>{this.state.value}</h2>
<NothingChanges />
</div>
);
}
}
6.5
Unmounting
Component is being removed from the DOM
componentWillUnmount() is where cleanup code such as invalidating timers and canceling ajax requests should go
6.6
{ Exercise }
Popular Programming Languages on GitHub
7.1
Forms in React
HTML form elements such as input, textarea or select,
maintain their state - user input - in the DOM
React provides two different approaches to form handling:
Uncontrolled Components - they work just like traditional HTML
forms, keeping and updating state in the DOM
Controlled Components - form state is managed by React just like
every other piece of state in the application
7.2
Uncontrolled Components
The browser stores and updates the value for each form input element
Whenever the value is needed it has to be pulled from the field
class Form extends React.Component {
handleSubmit = () => {
const value = this.input.value;
// do something with value
};
render() {
return (
<div>
<input type="text" ref={input => (this.input = input)} />
<button onClick={this.handleSubmit}>Sign Up</button>
</div>
);
}
}
Controlled Components
The React way for doing form handling,
where the React state is the single source of truth
Input values are pushed into form fields using a value from state or props
handleSubmit = () => {
// do something with this.state.text
};
render() {
return (
<div>
<input type="text" value={this.state.text} onChange={this.handleChange} />
<button onClick={this.handleSubmit}>Sign up</button>
</div>
);
}
}
Every state mutation will have an associated handler function, making it really easy to modify or validate user input
7.4
{ Exercise }
Developer Profile on GitHub
8.1
React Router
Provides a collection of navigational components,
composed declaratively in React applications
Everything is a component in React Router,
which means routing occurs when the app is rendering
In static routing, routes are declared before rendering takes place,
which is exactly the opposite of React Router dynamic routing
8.2
Rendering a Router
The Router receives a single child component
which should render the rest of the application
// use the browser based version
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render((
<BrowserRouter>
<App />
</BrowserRouter>
), document.getElementById('root'));
Route Matching
A Route component will render its content when
its path prop matches the current location pathname
import { Route } from 'react-router-dom';
The exact property will make the route match if the path property is exactly equal to the pathname
It makes sense to list a number of possible Routes next to each other,
but a Route component can be used anywhere to render content based on location
8.4
Grouping Routes
Routes can be grouped using a Switch component
<Switch>
<Route exact path='/' component={Home}/>
<Route path='/about' component={About}/>
<Route path='/contact' component={Contact}/>
{/* when none of the above match, <NoMatch> will be rendered */}
<Route component={NoMatch}/>
</Switch>
Path Parameters
It is possible to capture path parameters within a pathname
Named parameters are defined by prefixing : to the parameter name and
accessed through the match.params prop
// route config
<Route path='/users/:id' component={User}/>
Query String
The query string is available through the location.search prop
Any query string library such as the popular qs can be used to parse it
// import the popular qs library
import qs from 'qs';
// route config
<Route path='/users' component={User}/>
// /users?username=rui
return <h3>User Name: {queryParams.username}</h3>;
);
8.7
Navigation
Special components are required for navigation as
standard anchor tags would cause a page refresh
The Link component updates the URL and
changes the rendered content without reloading the page
// location = { pathname: '/react' }
Redirect
Navigation can be forced by rendering a Redirect component
function Admin({token}) {
if (!token) {
return <Redirect to='/login'/>;
}
{ Exercise }
Code Awards