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