FRONT-END DEV
Modern JavaScript
π¨βπ«Β Nicolas Payot
Front-End Developer @
Why this course?
Front-End Development is HUGE
And so is JavaScript ecosystem in 2019...
OUTLINE
PART 1 πͺ
OUTLINE
PART 2 πͺπͺ
1. Introduction to JavaScript
Make web pages alive
A bit of history...
1995 / 10 days / Brendan Eich
Ecma International
From Nov 1996 to Jun 1997
ECMAScript v1
ECMAScript
1
June 1997
Core syntax
ECMAScript
2
June 1998
Minor changes
ECMAScript
3
December 1999
Regular exp, try / catch, formatting for numeric output, ...
ECMAScript
4
Abandoned
Political differences about language complexity
ECMAScript
5
December 2009
"strict mode", JSON, Array prototype methods, getter / setter, ...
ECMAScript
6
June 2015
Classes, modules, for ... of, template literals, ...
ECMAScript
7
June 2016
Exponentiation operator (**), Array.prototype.includes
ECMAScript
8
June 2017
async / await, String padding, Object.values / .entries, ...
ECMAScript
9
June 2018
Async iteration, rest / spread properties, RegExp named capture groups, ...
ECMAScript
10
June 2019
Array.flat, Array.flatMap, Object.fromEntries, ...
2. Primitive data types
boolean
A logical entity that can have 2 values: true and false
const foo = true; // typeof foo => "boolean"
const bar = false; // typeof bar => "boolean"
null
An entity that exists but has no type or value
let foo; // typeof foo => "undefined"
const bar = null; // typeof bar => "object" (legacy reasons)
undefined
A variable that's not been assigned a value (β οΈ also a property of the global object)
let foo; // typeof foo => "undefined"
bar; // (window.bar) typeof bar => "undefined"
const baz = {};
baz.buzz; // undefined
number
An entity that's either an integer, floating point, or hexadecimal (integer)
const one = 1; // typeof one => "number"
const total = 10.1234; // typeof total => "number"
const hex = 0xFF; // (255) typeof hex => "number"
Number
number primitive wrapper
Number('1'); // 1
Number(false); // 0
Number(true); // 1
Number('hello'); // NaN
typeof NaN; // ?
Use to convert any value to a number
Number('1'); // 1
Number(false); // 0
Number(true); // 1
Number('hello'); // NaN
typeof NaN; // "number"
string
string literals or template literals (ES2015)
const hello = 'Hello, World!';
const name = 'John';
const helloJ1 = 'Hello, ' + name + '!';
const helloJ2 = `Hello, ${name}!`; // template literal
// helloJ1, helloJ2 => "Hello, John!"
3. Operators
Assignment operators
x = y
Assignment operators
x += y π x = x + y
Assignment operators
x -= y π x = x - y
Assignment operators
x *= y π x = x * y
Assignment operators
x /= y π x = x / y
Comparison operators
==
Returns true if operands are equal
Comparison operators
!=
Returns true if operands are not equal
Comparison operators
===
Returns true if operands are equal
AND of the same type
Comparison operators
!==
Returns true if operands are not equal
OR have different type
Comparison operators
>
Returns true if left operand is greater
than right operand
Comparison operators
>=
Returns true if left operand is greater than
or equal to right operand
Comparison operators
<
Returns true if left operand is less than right operand
Comparison operators
<=
Returns true if left operand is less than
or equal to right operand
Logical operators
&&
Returns true if left operand AND right operand is true
Logical operators
||
Returns true if left operand OR right operand is true
Logical operators
!
Returns false if its single operand can be converted
to true, otherwise true
Conditional (ternary) operator
condition ? val1 : val2
Returns val1 if condition is true
and val2 ifΒ condition is false
4. Type Coercion &
Falsy / Truthy values
Type coercion
Implicit conversion from a type to anotherΒ
const foo = '1';
const bar = 1;
foo == bar // true, coercion!
foo === bar // false
Type coercion
Implicit conversion to stringΒ
const ten = 10;
const thousand = '1000';
ten + thousand // ?
const ten = 10;
const thousand = '1000';
ten + thousand // "101000"
Type coercion
Implicit conversion to stringΒ
const names1 = [ 'Alice', 'Bob' ];
const names2 = [ 'John', 'Jane' ];
names1 + names2 // ?
const names1 = [ 'Alice', 'Bob' ];
const names2 = [ 'John', 'Jane' ];
names1 + names2 // "Alice,BobJohn,Jane"
Type coercion
Implicit conversion to stringΒ
const hundred = '100';
const truthy = true;
hundred + truthy // ?
const hundred = '100';
const truthy = true;
hundred + truthy // "100true"
Type coercion
Implicit conversion to numberΒ
const five = 5;
const four = '4';
five - four // ?
const five = 5;
const four = '4';
five - four // 1
Type coercion
Implicit conversion to numberΒ
const five = 5;
const four = [ 4 ];
five - four // ?
const five = 5;
const four = [ 4 ];
five - four // 1
Type coercion
Implicit conversion to numberΒ
const five = 5;
const numbers = [ '1', '2', '3' ];
five - numbers // ?
const five = 5;
const numbers = [ '1', '2', '3' ];
five - numbers // NaN
Type coercion
Implicit conversion to numberΒ
const five = 5;
const falsy = false;
five - falsy // ?
const five = 5;
const falsy = false;
five - falsy // 5
Type coercion
Implicit conversion to booleanΒ
const foo = 'foo';
const ten = 10;
foo || ten // ?
const foo = 'foo';
const ten = 10;
foo || ten // "foo"
When using || π if the first value casts to true, then it is returned
Type coercion
Implicit conversion to booleanΒ
function hello(name) {
return `Hello, ${name || 'Anonymous'}`;
}
hello('John'); // "Hello, John"
hello(); // "Hello, Anonymous"
Type coercion
Implicit conversion to booleanΒ
const foo = 'foo';
const ten = 10;
foo && ten // ?
const foo = 'foo';
const ten = 10;
foo && ten // 10
When using && π if both values cast to true, then second one is returned, else first falsyΒ value is returned
Falsy values
if (false)
if (null)
if (undefined)
if (0)
if (NaN)
if ('')
if ("")
if (document.all) // Legacy, browser detection
Truthy values
EVERYTHING
ELSE
5. Variables
var / let / const
Variables are named values and can be of any type
var hello = 'Hello, World!';
var FORTY2 = 42;
var _done = true;
var $$$ = 'money money';
Can start with letter, _ or $
var 2fast2furious = 'Vin Diesel';
var if = 'Nope, not working!';
var discount% = '10%';
π
π
var
GlobalΒ scope
var name = 'John Doe';
window.name // "John Doe"
β οΈ DO NOT DO THAT β οΈ
var
LocalΒ scope
function greetings() {
var fullName = 'John Doe'; // Local scope
return `Hello, ${fullName}`;
}
greetings();
fullName // Error: fullName is not defined
window.fullName // undefined
let (ES2015)
var a = 1;
var b = 2;
if (a === 1) {
var a = 11; // Global scope
let b = 22; // Block scope (if)
}
a // ?
b // ?
BlockΒ scope
var a = 1;
var b = 2;
if (a === 1) {
var a = 11; // Global scope
let b = 22; // Block scope (if)
}
a // 11
b // 2
const (ES2015)
const foo; // Error: missing initializer
const bar = 'bar';
bar = 'buzz'; // Error: Assignment to constant
const creates a read-only reference to a value
const (ES2015)
const names = [ 'Alice', 'Bob' ];
names.push('John');
names // [ "Alice", "Bob", "John" ]
BUT the variable is not immutable
6. Functions
Function declaration
A function declaration has a name, (optional) params and a body
function sayHi() {
console.log('Hi!');
}
sayHi(); // "Hi!", returns undefined
By default, a function returns undefined
Function declaration
With a return statement
function add(a, b) {
return a + b;
}
add(1, 2); // 3
Function declaration
Hoisting βοΈ
add(1, 2); // 3
function add(a, b) {
return a + b;
}
The function can be used before it was declared
Function expression
A function expression has a (optional) name, (optional) params and a body
const sayHi = function() { // Anonymous function
console.log('Hi!');
}
sayHi(); // "Hi!"
Function expression
With a name and params
const add = function addNumbers(a, b) {
return a + b;
}
add(1, 2); // 3
add.name; // "addNumbers"
A function expression has a name property
Function expression
Arrow function (ES2015)
const add = (a, b) => {
const sum = a + b;
return sum;
}
add(1, 2); // 3
Function expression
Arrow function (ES2015)
const increment = a => {
const b = a++;
return b;
}
increment(1); // 2
Arguments parentheses are optional when there's only 1
Function expression
Arrow function (ES2015)
const add = (a, b) => a + b;
add(1, 2); // 3
Shorter functions: when there's only a return statement
Function expression
Hoisting βοΈ
add(1, 2); // TypeError: add is not a function
var add = (a, b) => a + b;
β οΈ The function can NOTΒ be used before
it was declared
Constructor function
function User(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
const john = new User('John', 'Doe');
john.firstName; // "John"
john.lastName; // "Doe"
Constructor function
π Useful to create multiple objects with the same properties and methods
π Function Name should be capitalized (convention)
π Use of the newΒ keyword
Closure
function add(a) {
return function(b) {
return a + b;
}
}
const add10 = add(10); // add10 is a closure
add10(1); // 11
add10(2); // 12
add10 is a closure because it remembersΒ the environment in which it was created, when used later
7. Control structures
if / else
if (a > 10) {
// do something
} else if (a > 5) {
// do something else
} else {
// do something else, again
}
In if (condition), condition is considered to be either truthy of falsy
switch
switch (color) {
case 'RED':
// do something when color === 'RED'
break;
case 'BLUE':
// do something when color === 'BLUE'
break;
default:
// do something when color is not 'RED' or 'BLUE'
}
switch
switch (x) {
case 1:
console.log(1);
break;
case 2:
console.log(2);
default:
console.log(-1);
}
Here, what happens if x = 2?
β οΈ 2 andΒ -1 will be printed because break is missing!
for loop
const names = [ 'Alice', 'Bob', 'John' ];
for (let i = 0; i < names.length; i++) {
console.log(names[i]);
}
>> Alice
>> Bob
>> John
Old school way... π
for loop
const names = [ 'Alice', 'Bob', 'John' ];
for (let name of names) {
console.log(name);
}
>> Alice
>> Bob
>> John
for ... of: better! π (ES2015)
while loop
let n = 0;
let x = 0;
while (n < 3) {
n++;
x += n;
}
// x = ?
The loop executes itself until the condition evaluates to false
let n = 0;
let x = 0;
while (n < 3) {
n++;
x += n;
}
// x = 6
8. Data structures
Object
Object litteral syntax
const book = {}; // Empty object
const book = { // Or with properties
title: 'A Game of Thrones',
published: new Date('August 1, 1996'),
author: {
name: 'George R. R. Martin'
}
};
Object
Set properties
book.title = 'A Clash of Kings';
// or
book['title'] = 'A Clash of Kings'
// Nested property
book.author.birth = new Date('September 20, 1948');
β οΈ TypeError if author is not defined (needs to be at least an empty object)
Object
Get properties
const bookTitle = book.title;
// or book['title']
const authorName = book.author.name;
// or book['author']['name']
console.log(bookTitle); // A Clash of Kings
console.log(authorName); // George R. R. Martin
Object
Destructuring (ES2015)
const { title } = book;
const { name } = book.author;
console.log(title); // ?
console.log(name); // ?
const { title } = book;
const { name } = book.author;
console.log(title); // A Clash of Kings
console.log(name); // George R. R. Martin
Array
// Empty array creation
const emptyArray = [];
// Array creation with elements
const names = [ 'Alice', 'Bob', 'John' ];
console.log(names.length); // 3
An Array is a list-like object
β οΈ length property is not fixed and can be changed any time
Array
const names = [ 'Alice', 'Bob', 'John' ];
names[0]; // "Alice"
names[1]; // "Bob"
// Get last element
names[names.length - 1]; // "John"
Accessing elements
Array
const names = [ 'Alice', 'Bob', 'John' ];
const [alice] = names;
console.log(alice); // Alice
const [, , john] = names;
console.log(john); // John
Destructuring (ES2015)
Array
const items = [ 'Alice', 'Bob', 'John' ];
items[2] = 'Jane';
items.push(100);
console.log(items); // ?
Setting elements
const items = [ 'Alice', 'Bob', 'John' ];
items[2] = 'Jane';
items.push(100);
console.log(items); // ["Alice", "Bob", "Jane", 100]
Array
const names = [ 'Alice', 'Bob', 'John' ];
names.forEach(name => {
console.log(name);
});
>> Alice
>> Bob
>> John
Array.prototype.forEach
Loop through items, does not return anything
Array
const names = [ 'Alice', 'Bob', 'John' ];
const fnames = names
.filter(name => name.length > 3);
console.log(fnames); // ["Alice", "John"]
Array.prototype.filter
Returns a new array where each items verifies the given condition
Array
const names = [ 'Alice', 'Bob', 'John' ];
const newNames = names
.map(name => name.substring(0, 2));
console.log(newNames); // ["Al", "Bo", "Jo"]
Array.prototype.map
Returns a new array with transformed items
Array
const numbers = [ 1, 2, 3 ];
const sum = numbers
.reduce((total, number) => total += number);
console.log(sum); // 6
Array.prototype.reduce
Returns a single value by applying an accumulator function to each items (reducing)
9. this keyword
Global context
this
console.log(this); // Window { ... }
var one = 1;
console.log(window.one); // 1
console.log(this.one); // 1
this.two = 2;
console.log(two); // 2
console.log(window.two); // 2
Inside a function
this
function add(a, b) {
return a + b + this.c;
}
var c = 3;
add(1, 2); // 6
add is called within global context
Inside a function
this
function add(a, b) {
return a + b + this.c;
}
var c = 3;
const obj = { c: 4 };
add.call(obj, 1, 2); // ?
// or add.apply(obj, [1, 2]);
add is called within obj context (π‘call:Β columns,Β apply:Β array)
function add(a, b) {
return a + b + this.c;
}
var c = 3;
const obj = { c: 4 };
add.call(obj, 1, 2); // 7
// or add.apply(obj, [1, 2]);
Object method
this
add is called within obj context
var a = 1;
const obj = {
a: 2,
add: function(b, c) {
return this.a + b + c;
}
}
obj.add(2, 3); // ?
var a = 1;
const obj = {
a: 2,
add: function(b, c) {
return this.a + b + c;
}
}
obj.add(2, 3); // 7
this
thisΒ is bound to the new object being constructed
function User(name) {
this.name = name;
}
const john = new User('John Doe');
console.log(john.name); // John Doe
Constructor function
Arrow function
this
thisΒ retains the value of the enclosing lexical context's this
var a = 1;
const obj = {
a: 2,
add: (b, c) => {
return this.a + b + c;
}
};
obj.add(2, 3); // ?
var a = 1;
const obj = {
a: 2,
add: (b, c) => {
return this.a + b + c;
}
};
obj.add(2, 3); // 6
11. ES2015 classes
ES2015 classes are syntax sugar over prototype-based inheritance
class Person {
constructor(name) {
this.name = name;
}
who() {
return `Hi, I'm ${this.name}`;
}
}
ES2015 class
const john = new Person('John');
john.who(); // "Hi, I'm John"
console.log(john); // { name: "John" }
console.log(Person.prototype); // { who: f }
ES2015 class
class Developer extends Person {
constructor(name, language) {
super(name);
this.language = language;
}
}
const jane = new Developer('Jane', 'JavaScript');
jane.who(); // "Hi, I'm Jane"
console.log(jane.language); // JavaScript
ES2015 class
Subclassing with extends
12. ES2015 modules
π Encapsulates code into a single unit Β
What's a module?
π 1 module per file / 1 file per module
π Export objects and functions so that they're available to other modules
// file foo.js
export default class {
constructor() { ... }
}
export
default export
There can only be 1 default export per file
// file bar.js
export default function() { ... }
// file baz.js
export default { ... }
// file dev.js
export class Developer { ... }
export function hire(developer) { ... }
export const FMKS = [ 'React', 'Vue', 'Angular' ];
export
named export
There can be multiple named exports per file
import Foo from './foo.js';
import bar from './bar.js';
import baz from './baz.js';
import
Importing defaults
Foo, bar, baz can have any other names
import { Developer, hire, FMKS } from './dev.js';
import
Importing named exports
import * as dev from './dev.js';
const alice = dev.Developer('Alice', 'JavaScript');
dev.hire(alice);
alice.chooseFramework(dev.FMKS);
13. Handling DOM
π Document Object Model Β
DOM
π Programming interface for HTML
π Represents the document (web page) as nodes and objects
DOM
HTML attribute vs DOM property
<h1 class="title hello">Hello, World!</h1>
π An attribute is always a string, its value is static (written in the HTML code)
h1.getAttribute('class'); // "title hello"
h1.className; // "title hello"
h1.classList; // [ "title", "hello" ]
π A property is not always a string, its value is dynamic
DOM
Creating an Node element
const h1 = document.createElement('h1');
h1.textContent = 'Hello, World!';
document.body.appendChild(h1);
<body></body>
<body>
<h1>Hello, World!</h1>
</body>
DOM
Accessing a Node element
// Get element(s) by type
const h1 = document.querySelector('h1');
<body>
<h1>Hello, World!</h1>
</body>
π querySelector function takes a CSS selector as argument
DOM
Accessing a Node element
// Get element by id
const h1 = document.querySelector('#title');
<body>
<h1 id="title">Hello, World!</h1>
</body>
DOM
Accessing a Node element
// Get element(s) by class
const lis = document.querySelectorAll('.name');
<ul>
<li class="name">John</li>
<li class="name">Jane</li>
<li class="name">Alice</li>
</ul>
DOM
Accessing a Node element
// Get element(s) by attribute
const input = document
.querySelector('[name="search"]');
<input name="search">
DOM
Removing a Node element
const h1 = document.createElement('h1');
h1.remove();
<body>
<h1>Hello, World!</h1>
</body>
<body></body>
14. Asynchronous
π User interactions
π Ajax requests
π setTimeout, setInterval
Asynchronous stuff in JS
β οΈ JavaScript is single threaded (in the browser)
Asynchronous
Callback
window.addEventListener('click', $event => {
console.log($event.clientX, $event.clientY);
});
// or
window.onclick = $event => {
console.log($event.clientX, $event.clientY);
};
A callback is a function passed into another function as an argument
Asynchronous
Callback
setTimeout(() => {
console.log(`I'm 1 second late`);
}, 1000);
// or
function message() {
console.log(`I'm 1 second late`);
}
setTimeout(message, 1000);
Asynchronous
Promise
Completion (or failure) of an async operation and its resulting value
π Pending / Resolved / Rejected
Asynchronous
Promise
fetch('/api/names').then(response => {
// Promise was resolved
if (response.status === 200) {
...
}
}, error => {
// Promise was rejected
console.error(error);
});
Here, the Promise object is returned by fetch() function call
Asynchronous
Chaining promises
function toUpperCase(names) { ... }
fetch('/api/names')
.then(response => response.json())
.then(data => {
const { names } = data; // [ "John", "Jane" ]
return toUpperCase(names);
})
.then(names => {
console.log(names); // [ "JOHN", "JANE" ]
});
Asynchronous
Creating a Promise...
function getBurgers() {
return new Promise(resolve => {
setTimeout(() => {
resolve('πππ');
}, 1000);
});
}
getBurgers().then(burgers => {
// After 1 second
console.log(burgers); // πππ
});
...that will be resolved after 1 second
Asynchronous
Creating a Promise...
function getBurgers() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('πππ');
}, 1000);
});
}
getBurgers().then(() => {}, eggplants => {
// After 1 second
console.log(eggplants); // πππ
});
...that will be rejected after 1 second
Asynchronous
async / await (ES2017)
function getBurgers() { return new Promise(...); }
function getBeers() { return new Promise(...); }
async function menu() {
const burgers = await getBurgers();
const beers = await getBeers();
console.log(burgers, beers); // πππ, πΊπΊπΊ
}
menu();
Allow async code to be handled in a synchronous way
Asynchronous
async / await (ES2017)
function getBurgers() { return new Promise(...); }
async function menu() {
try {
const burgers = await getBurgers();
} catch (eggplants) {
console.log(eggplants); // πππ
}
}
menu();
Errors are handled with try ... catch block
15. Ecosystem /
tools & libraries
A JavaScript utility library
THE package manager for JavaScript
Fast, reliable and secure dependency management
The compiler for writing next generation JavaScript
Module bundler: bundle JavaScript files for usage in the browser
Front-End Dev: Modern JavaScript
By Nicolas Payot
Front-End Dev: Modern JavaScript
- 1,385