Skip to content

Instantly share code, notes, and snippets.

@Thomasorus
Last active November 9, 2020 22:39
Show Gist options
  • Save Thomasorus/0db8a9d6bfff54780638bbbb8e10d467 to your computer and use it in GitHub Desktop.
Save Thomasorus/0db8a9d6bfff54780638bbbb8e10d467 to your computer and use it in GitHub Desktop.

Javascript lessons

Types

There's 7 types:

  • String
  • Number
  • Boolean
  • Null
  • Undefined
  • Symbol
  • Object

Don't forget: everything in Javascript is an oject. All others than Object are referred to primitive types.

Strings

Holding text. Three ways of declaring them:

const single = 'tom';
const double = "tom";
const back = `tom`;
  • A string using backquotes is called a template litteral.
  • A concatenation is done with the + symbol in javascript.
  • An interpolation is when you put a variable inside of a string.

Favor interpolation instead of concatenations :

const name = "Thomas";
const phrase = `My name is ${name}, nice to meet you.`

Numbers

const integer = 100;
const float = 100.5;

With numbers there's some helper methods : Math.round() to round a float to the closest integer, Math.floot() for the lowest integer, Math.ceil() for the uppest integer, Math.random() for a random number.

There addition, soustraction, multiply and divide, there's modulo and power . Modulo (%) returns the remainder after division of one number by another. Power multiplies the value by itself (use ** for example 10 ** 2 will return 100).

Beware of floating points! Never store as floats values that needs to be processed, like money.

Infinity and Negative Infinity exist in javascript. If you go higher than what the computer can calculate, it will return Infinityor -Infinity. Their type is number.

Nan is of type Number but indicates that it's not a number. Yes, not a number is a number.

Objects

Everything in Javascript is an object. Objects are used to create collections of data or functionnalities. The basic usage is for example:

const person = { 
  name = "Thomas";
  age = 35;
};

There is no order in objects, as opposed to arrays. They you can access it using person.name and person.age.

Null and Undefined

There's two ways of express nothing in Javascript. They are both nothing

  • Undefined is something (a variable for example) that has no value yet.
  • Null is something that has a value of nothing.

Booleans and Equality

Boolean is true or false and that's it. But Booleans can be calculated and compared.

10 === 10 // Returns true
10 === 100 // Returns false

Beware of type checking. === checks for the type, == does not!

"10" == 10 // Returns true
"10" === 100 // Returns false

Functions

Functions are used to regroup statements and can take in data, called arguments, and sometimes returns a value. The methods of Javascript like Math.max() are functions existing into the programming language.

Notes on parameters and arguments:

  • Parameters are the definition of the values the function accepts : function test(param1, param2) { ... }
  • Argumentes are the values you send to the function when you use it: test(arg1, arg2);
  • You can give a basic value to a parameter that will be overwritten by the argument: function test(param1, param2 = 2) {...}

Functions basics

Functions are are a first class citizen in Javascript, which means they are a kind of type by themselves, as you are able to pass, return and assign them.

There are several basic ways of creating functions.

//Basic way
function doctorize(firstname) {
  return `Dr. &{firstname}`
}
//Anonynous function work in certain cases
function(firstname) {
  return `Dr. &{firstname}`
}
//Function expression are using anonymous functions as a type
const doctorize = function(firstname) {
  return `Dr. &{firstname}`
}

Using function expressions can create some problems. As they are a variable, they can't be hoistered to the top of the file when the Javascript interpreter reads the file. So if a function expression is used before it is declared, it won't work.

Arrow functions

Then they are arrow functions. Their syntax are more simple and they don't have their own scope (the $this keyword). Arrow functions are anonymous by default.

You can replace the word function and replace it by a fat arrow right after the arguments:

const inchToCM = (inches) => {
  return inches * 2.54;
}

You can also remove the return statement by putting the function on one line and removing the curly brackets.

const inchToCM = (inches) => inches * 2.54;

If there is only one argument, the parenthesis are useless.

const inchToCM = inches => inches * 2.54;

You can also use function to return an object but it requires a special syntax to avoid that curly brackets of the object are interpreted as a block of code. So this:

function makeABaby(first, last) {
  const baby = {
    name: `${first} ${last},
    age: 0
  }
  return baby;
}

Becomes this where parenthesis are used:

const makeABaby = (first, last) = > ({ name: `${first} ${last}, age: 0 })

It's not very readable so it's not an obligation to use them.

IIFE - Immediateley Invoked Function Expression

IIFE is used to immediately run a function when the code is loaded. You put a function inside parenthesis as their are read first, and then use a double parenthesis behind to declare it as a function.

(function() {
  console.log('Running IIFE');
  return 'Done';
 })();

Methods

A method is a function that lives inside an object. For example in console.log(), console is an object and log() is the function.

const Thomas = {
  name: 'Wes Bos',
  //Classic way
  sayHi: function() {
    console.log('Hey Thomas');
    return 'Hey Thomas';
   }
   //Short hand method
  yellHi() {
    console.log('HEY THOMAS');
  }
  //Arrow function methoed
  wisperHi: () {
    console.log('Hi Thomas, I'm wispering);
  }
}

Callback function

A callback function is an anonymous function called by another function at a later point in time.

button.addEventListener('click', function() {
  console.log('Nice job !');
});

setTimeout(function() {
  console.log('This is the time');
}, 1000);

setTimeout(() => {
  console.log('This is the time');
}, 1000);

Debugging tools for javascript tips and tricks

You can select something with the inspector and use $0.value to get its value instead of selecting it by id or class. You can do a queryselector or queryselectorall with $ or $$.

Scope

Basically, where are my functions and variables available? A variable in a file in the wild is called a global function and if is declared using var, is available throught the window object. Functions are available throught the window object too.

  • Function scope is means that everything in the function is only available in the function unless we return it.
  • Block scope (for ex an if statement) does not allow the use of the variables outside itself except if declared with var.

Javascript has lexical scoping / static scoping. It means that variable/scope lookup doesn't happen where they are run but where they are defined. For example:

const dog = "loulou";
function logDog() {
  console.log(dog);
}
 
function go() {
  const dog = "fifi";
  logDog();
}

go();
//Result is loulou and not fifi

Hoisting

Basically, when javascript is executed, functions declarations are moved to the top, so you can execute a function and declare it after. It really depends of the mindset of the developer. Some prefer running functions first as a "what does this file do" and put functions declarations after as "how does that work".

For variables hoisting, Javascript will create the missing variables when code is hoisted but since it doesn't know their values, they will be set to undefined and then updated as the file is parsed.

Closures

A closure is the ability the access the parent scope from a child scope, even after the parent function has been terminated.

function outer() {
  const outerVar = "Outer!";
  function inner() {
    const innverVar = "Inner !";
    console.log(innerVar);
    console.log(outerVar);
  return inner;
}

const innerFunction = outer();
innerFunction();
//Returns "Outter!" and "Inner";

In this example, outer() is executed when assigned to innerFunction, and you can now execute inner. So you could think that, since we now have inner() instead of outer() in the variable, you can't access outerVar. But it actually works as outerVar is stored in memory for use at a later time.

Closures can be used to create private variables from the same variable. For example:

function createGame(gameName) {
  let score = 0;
  return function() {
    score++;
    return `Your ${gameName} game score is ${score}`;
  }
}
const footballGame = createGame('football');
//Returns : "Your football game score is 1"
//Executed again : "Your football game score is 2"
//Etc...

const rugbyGame = createGame('rugby');
//Returns : "Your rugby game score is 1"
//Executed again : "Your rugby game score is 2"
//Etc...

Here despite using the same function to create a game, their scores are separated.

The DOM (document object model) and javascript

In the rare case where you can't move the javascript file after the html, use : document.addEventListener('DOMContentLoadeded', init);.

Today to select elements on the page:

  • document.querySelector('p'); returns the first element.
  • document.querySelectorAll('p'); returns a nodelist of elements.

To get the content of an element:

  • .textContent() will return both the text but also script and style tags and their content.
  • .innerText() returns only the text.
  • .innerHtml() returns the html inside an element.
  • .outerHtml() returns the html inside an element + the container element.

The insert stuff into the textContent:

  • .inserAdjacentText() has multiple positions where you can insert content (beforebegin, beforeend, afterbegin...)

To get data-attributes:

  • myObject.dataset.nameOfMyAttribute

To create html:

  • const myP = document.createElement('p');
  • Then insert it: document.body.appendChhild(myP); or `document.body.insertAdjacentElement('beforebeing', myP);

It's possible to create an html object from a string using a range instead of using .innerHtml(). The Range interface represents a fragment of a document that can contain nodes and parts of text nodes:

const myHTML = `
<div class="wrapper">
  <h2>Thing</h2>
</div>
const myFragment = document.createRange().createContextualFragment(myHTML);

The user might add html into the string you ask him to enter inside an input. This is cross side scripting (XSS). See the security part.

It's possible to traverse the dom nodes or remove them:

  • .children
  • .firstElementChild
  • .lastElementChild
  • .previousElementSibling
  • .nextElementSibling
  • .parentElement
  • .remove

Events

Event listeners

Dom elements create events when they change. To listen to them, use event listeners. An event listener takes a type of event it needs to listen and a function as a second agument. Connecting a dom element with an event listener is often called 'binding'.

myDomEl.addEventListener('click', function() {
  console.log('click');
});

It's possible to remove an event listener with .removeEventListener but only if a named function or an arrow function stored into a variable is used. Anonymous functions cannot be removed.

It's possible to listen to multiple elements, for example various buttons with the same class.

const buttons = document.querySelectorAll('.btn');
buttons.forEach(function(button) {
  button.addEventListener('click', function() {
    console.log('click');
  });
});

The event object

If you pass a parameter in the function of an addEventListener, you can recover the event itself.

myDomEl.addEventListener('click', function(event) {
  console.log(event);
});

This code returns a PointerEvent with a lot of objects inside like isTrusted, pressure, pointerType, etc...

Targets

To recover the element you just clicked, use event.target. Once it's done you can recover everything related to the button itself. For example you can also recover data attributes in the event object using event.target.dataSet;

What happens when you have nested elements inside the element you are listening to? If you use event.target you'll get both. To get the element that fired the listener, you need to use event.currentTarget.

Propagation

When you trigger an event listener, the event will propagate to its parents to allow, in the case of one of them also had an event listener, to be triggered too. This is called event propagation and when it's ascending from the element to its parents, it's called event bubbling. It can be stopped using event.stopPropagation to only recover the triggered item.

The opposite of event bubbling is event capturing, where the event goes from the parent element to the children elements. You can use it by adding capture : true as the last argument in the event listener declaration. It's also possible to use event.stopPropagation but it will then do the opposite: instead of isolating the element triggering the eventm it will isolate the parent.

PreventDefault

Some elements in html have a default event when triggered. It's possible to stop them using event.preventDefault();

Accessibility

  • Use semantic html, don't missuse buttons and links for example.
  • When an element is not clickable by default, use keyup instead of click.
  • When using preventDefault on a button or link that changes the page, you have to vocalize the change. If not, a blind person can't know you changed pages.
  • Probably more stuff.

Logic and Flow Controls

Bedmas

The order in wich operators execute in javascript is the same as in mathematics:

  • brackets / parenthesis
  • exponent
  • division
  • multiplication
  • addition
  • substraction

Regex

Regex start and end with a /. If it ends with /g it means global, so it will search for all occurences of the terme searched.

Truthy, Falsy

By default values in variables, despite of their type, are kinda true or kinda false. Truthy and falsy are a way of simplifying flow statements.

Are thruthy:

  • 1
  • -10 and all other numbers except 0
  • string
  • array even if empty
  • object even if empty

Are falsy:

  • 0
  • undefined
  • null
  • NaN
  • empty string

Coercion

The act of transforming a type into a boolean. A single bang ! will give the opposite of their thruthy/falsy, and a double bang !! will convert them to a real boolean.

Ternaries

Short hand if statement : let word = count === 1 ? 'item : 'items'; You can abuse it by using && : isAdmin && showAdminBar();

Intervals and Timeout

setTimeout(function() { console.log('Time')}, 500); allows to console log after 500 milliseconds. setIntervals(function() { console.log('Time')}, 500); allows to console log every 500 milliseconds

Data Types

Objects

Everything is an object in Javascript. Objects allow to group different values, giving them a key and a value. Be careful that objects are used when the order of it's values doesn't matter, unlike arrays. If you declare an object in a const, it's possible to modify the values inside but you can't redeclare a value with the same key. To forbid changing an object, you can use object.freeze.

When using a variable as a value for an object and both the key and the variable have the same name, there's no need to write the key:

const age = 100;
const person = {
  age,
  name: "thomas",
  things: {
    thing1: "thing",
    thing2: "thing2",
};
const personFroze = Object.freeze(person);

To delete a property, use delete : delete person.age.

Methods

A method is a function inside an object. When using it, this takes the parent object. In this case, this is person:

const age = 100;
const person = {
  name: "thomas",
  sayHi: function(hi = "hi") {
    return `${hi} ${this.name}`
};
const personFroze = Object.freeze(person);

Object reference vs values

As opposed to variables, even if two objects have the same content, they are not considered the same and comparing them will return false.

When objects and arrays are copied (for example const object2 = object1), any update to object2 will also change object1. This happens because object2 is not a real copy of object1, it's a reference pointing to it. It's the same if you pass an object as an argument in a funciton.

So how do you copy an object?

Copy an object

  • You can use a spread operator: const object2 = {...ob ject1} that will navigate inside object1 and copy each value.
  • Or you can use the assign() method: const object2 = Object.assign({}, object1);

But doing this goes only one level deep and the deeper levels are still references. This is called a shallow copy. To do a deep copy or clone you need a library like lodash and its cloneDeep() function.

Merge two objects

To merge two objects, it's also possible to use the spread operator: const object3 = {...object1, ...object2}. If two keys have the same name, the last one will be the one used.

Maps

Maps are different than object has they allow to use any type for the key instead of just a string. This allows to create dictionnaries. You can get the size of a map using map.size and the order of elements in a map is guaranteed.

const myMap = new Map();
myMap.set('name', 'thomas');
myMap.set(100, 'This is a number');

//Will return:
Map(2)
  size: 2
  <entries>
    0: name → "thomas"
      <key>: "name"
      <value>: "thomas"
    1: 100 → "This is a number"
      <key>: 100
      <value>: "This is a number"

There are several methods for maps: .set(), .get(), .delete(). Using a map as a dictionnary can be very useful, for example:

const score = 200;
const prizes = new Map();
prizes.set(100, 'bronze');
prizes.set(200, 'silver');
prizes.set(300, 'gold');
console.log(`You win ${prizes.get(score)}`);
//Will return: "You win silver"

It can also be usefull in a loop, using destructuring:

for (const [points, prize] of prizes) {
  console.log(`${points} - ${prize})
 }

Use a map when the order needs to be maintained. The downside of maps is that there is no literal declaration (you have to use set, get, delete) outside of using an array of arrays: new Map([['name', 'thomas'], ['age', 35]); which can be a little strange. Also maps cannot store methods and you can't stringify a map into JSON without converting it to an object before, for example: const object = Object.fromEntries(myMap);.

Arrays

An array is used to store data in a specific order. Each thing inside an array is called an item and it's position is called the index. There are no keys in arrays. To test if a variable is an array, use the .isArray() method. Arrays are zero based, which means they start at 0.

Be careful that some array methods are mutable methods (like reverse()) can mutate the array and others called immutable methods don't (.slice()). In the case if you don't want to mutate an array, copy it first into a new variable using the spread operator, then use the mutable method: const array2 = [...array1].reverse();.

To add items to the end of the array, use .push(). Since it's a mutable method, use the spread operator: const array2 = [...array1, 'new val'];. To add at the front of the array, use unshift(). To add items in the middle, use slice inside a spread operator: const array2 = [...array1.slice(0, 2), "new", ...array1.slice(2)];.

You can get the index of an item by using the .findIndex() method. To return an index based on the value of an item, you can use a kind of loop, like this: const thomasIndex = names.findIndex(name => name === "thomas");.

Static arrays methods

Static methods are method that live in the Array object.

  • Array.of('1', '2') allows to declare an array.
  • Array.from({lenght: 10}) creates an array with 10 items. Array.from({lenght: 10}, function (item, index) {return index;}) returns an array where the value of each item is it's index.
  • Array.entries(object) will transform the content of an object into items inside the array.
  • Array.keys(object) will return the keys of an item.
  • Array.values(object) will return the values of an item.

Instance arrays methodes

Methods that lives in all arrays.

  • join() will turn all the arrays into a string and can take an argument as a separator.
  • split() can turn a string into an array
  • pop() returns the last item of the array
  • shift() adds an item at the start of the array
  • includes() allows to check if a value is in an array and returns a boolean

Callbacks methods

  • find() returns the value of the first element in the provided array that satisfies the provided testing function.
  • filter()creates a new array with all elements that pass the test implemented by the provided function.
  • some() tests whether at least one element in the array passes the test implemented by the provided function. It returns a Boolean value.
  • every() tests whether all elements in the array pass the test implemented by the provided function. It returns a Boolean value.
  • sort() sorts the elements of an array in place and returns the sorted array.

Looping and interating

There are several ways of looping on an array.

forEach()

array.forEach(function(item) {
  console.log(item)
 });

map()

Map is like a machine that takes data and returns it transformed. It's not mutating the existing array items, it basically mirrors its structure and changes the value according to the task demanded.

const arrayOfNames = ['thomas', 'coralie'];
function capitalize(name) {
  return `${name[0].toUpperCase()}${name.slice(1)}`;
}
const capitalizedNames = arrayOfNames.map(capitalize);
console.log(capitalizedNames)

It can be used on an array of objects.

Filter

Returns a subset of the items. Creates a new array with all elements that pass the test implemented by the provided function: const over40 = peopleList.filter(person => person.age > 400);

Higher Order Functions

It's when you put a function inside a function.

function findByProp(prop, propvalue) {
  return function isStudent(student) {
    return student[prop] === propvalue;
  }
}

Reduce

The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in single output value.

Needs more work

For, for in, for of and while

Basic looping is with for:

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

For of allows to loop over values. It's also useful for sequences of promises.

for(const letter of name) {
  console.log(letter)
}

For in allows to loop over the keys.

for(const prop in name) {
  console.log(prop)
}

Good to know: when using Object.entries to get access to the content of an object, you don't acces the data stored inside the prototype. For in allows to see the keys stored in the prototype.

While runs indefinitely until a condition is satisfied.

let cool = true;
i = 0;
while (cool === true) {
  console.log("you are cool");
  i++;
  if (i > 100) {
    cool = false;
  }
}

Object Oriented Programming

Everything is an object in JavaScript because every type has methods attached to it.

New

When using new you create an instance of an object. Variables and objects don't need it because they have shortcuts declaration but some types of objects don't, like dates: const myDate = new Date();. But you can also create you own types of objects.

This

The think keyword refers to the instance of an object that a function is bound. It means that this is going to be bound to what it is attached to. The this keyword is always bound to a function. This can also be used to store informations inside the object.

function Sandwich(toppings = [], customer) {
  this.toppings = toppings;
  this.customer = customer;
}

const jambonBeurre = new Sandwich(["jambon", "beurre"], thomas);

Prototype

If you create an instance of an object with new but want all instances to share some code (like methods or variables) you can use the prototype to store them. For example for an eat() function inside Sandwich, instead of duplicating it, store it inside the prototype.

function Sandwich(toppings = [], customer) {
  this.toppings = toppings;
  this.customer = customer;
  this.bites = 10;
}

Sandwich.prototype.eat = function() {
  if(this.bites >  0) {
    this.bites = this.bites -1;
  } else {
    console.log("No bites left");
  }
}

bind, call and apply

bind

.bind() allows to change the this of a function. For example:

const person = {
  name: 'Thomas',
  sayHi() {
    return `hey ${this.name}`;
  }
}  

const coralie = {name: "coralie"};
const sayHi = person.sayHi().bind(coralie);

Using sayHi() will return "hey coralie" instead of thomas because the bind changed the this to coralie's this.

call

Does the same thing as bind() but also call the function.

apply

Same as call but only accepts a single array of arguments.

Flow control

JavaScript is a single threaded language which means only one thing can be run at the same time. Since JavaScript is asynchronous it doesn't stop when it sees something that might take time like a timeOut() function.

The event loop

There are three things to remember to get how JavaScript works:

  1. The Call Stack is what the JavaScript interpreter is reading, basically code from to to bottom.
  2. The Web Apis is where the JavaScript interpreter store what is waiting or what is listenned to. When something finishes or happen, it's sent to the callback queue.
  3. The Callback Queue is where the Call stack comes to get some extra work once it doesn't have anything left to read.

The event loop is the thing that checks if the call stack is done and if things from the callback queue can be send to it for execution.

Promises

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment