Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Learn JavaScript

Download as pdf or txt
Download as pdf or txt
You are on page 1of 74

Sold to

tom.a.scott@hotmail.co.uk

JavaScript
Notes

Lydia Hallie
JavaScript Fundamentals 4
1.1 Primitive Data Types 4
1.2 Variables 5
1.2.1 Var, const and let 6
1.2.2 Coercion 6
1.3 Operators 6
1.3.1 Assignment operators 7
1.3.2 Comparison operator 7
1.3.3 Arithmetic operators 8
1.3.4. Logical operators 9
1.3.5 Operator precedence and associativity 10
1.4. Conditionals 12
1.4.1 If-else statements 12
1.4.2 Conditional operator 12
1.4.3 Switch statements 13
1.5 Arrays 14
1.6 Objects 15
1.6.1 Dot Notation 15
1.6.2 Bracket Notation 15
1.6.3 Dot Notation vs. Bracket Notation 16
1.6.4 Object methods 17
1.7 Functions 18
1.7.1 Function expressions 19
1.7.2 Function statements 19
1.7.3 Arrow functions 20
1.7.4 IIFE 21
1.7.5 Callback Functions 21
1.7.6 Promises 22
1.7.7 Async/await 24
1.8 Loops 25
1.8.1 For loops 25
1.8.2. For/in loops 26
1.8.4 Do/while loops 27
1.8.5 Break and continue 28
1.9 Common Methods 28
1.9.1 String methods and properties 28
1.9.2 Array methods and properties 32
1.9.3 Math Object 38
1.10 DOM Manipulation 40
1.10.1. DOM Methods and Properties 41
1.10.2. Bubbling and Capturing 44
1.10.3. Prevent default 46

1
Understanding JavaScript
2.1 Syntax Parser 46
2.2 Creation phase 46
2.2.1 The this keyword 47
2.3 Lexical Environment 47
2.4 Creation and hoisting 48
2.5 Execution stack 49
2.5.1 Event Loop 51
2.6 Variable scope 52
2.7 The scope chain 53
2.8 Closures 54
2.9 Closures and callbacks 57
2.10 bind(), call(), and apply() 58
2.11 Functional programming 59
2.11.1 Higher-order functions 59
2.12 Objects 60
2.12.1 Computed member access operator 60
2.13 JSON and Object Literals 61
2.14 Functions are objects 61
2.15 Function statement vs. function expression 62
2.16 By value vs. by reference 62
2.17 The keyword arguments and the spread operator 63
2.18 Inheritance 64
2.18.1 Understanding the prototype 64
2.19 Primitive or object 66
2.20 Function constructors and the keyword new 66
2.21 Prototype 67
2.22 Built-in function constructors 68
2.23 Classes 70
2.24 Static methods 71
2.25 Polyfill 72
2.26 Strict mode 72

2
This is a summarized collection of personal notes that were taken in order
to learn JavaScript, and combines both basic ES5 and ES6 features. This
book is not meant to replace any courses or other study methods, and
may contain information that is outdated or incomplete.

3
JavaScript Fundamentals

1.1 Primitive Data Types

JavaScript is a ​dynamically typed programming language​. It basically


means that we can ​declare variables​ with a value with a certain ​type​,
and later redeclare that variable with a value of a different type. The
variable’s data type is the JavaScript engine’s interpretation​ of the
type of data that variable is currently holding. JavaScript has ​six
primitive data types​:

boolean Represents a logical entity, ​true​ or ​false.

null Represents a lack of existence. It is safe to set a variable


to null.

undefined A variable that hasn’t been assigned a value yet, ​but it


has already been declared​, has the value ​undefined​. It
is not safe to set a variable to undefined, as it can cause
confusing during debugging.

number Represents a floating point number. There are always


decimals in JavaScript, even if you don’t see them.
For example: ​10

string Represents a sequence of characters.


For example:​ ​"Ten."

symbol A symbol is a ​unique​ and ​immutable​ value. This is new


in ES6.

4
1.2 Variables

Variables are ​containers​ that you can store ​values​ in. In the first
example, we declare a variable, then give it a value.

let​ greeting; ​// We are declaring a variable.


greeting = ​"Hello"​; ​// We are giving the variable a value.

Normally, you wouldn’t take these two steps. You’d simply type:

let​ greeting = ​"Hello"​;

Instead of the ​let​ keyword, you could in some cases also use ​var​ or
const​, however they are not the same.

JavaScript is a ​dynamically typed language​, which means that the


types of values can change at runtime, unlike other programming
languages. The JavaScript engine will determine the type. It basically
means is that we can do this:

let​ myNumber = 5;
myNumber = ​"five"​;

First, we gave the variable​ ​myNumber​ the value​ ​5​, which ​type​ is a
number​. Later, we redeclare the variable ​myNumber​ ​and give it the value
of​ ​"five"​, which type is a ​string​. This phenomenon is called ​coercion​.

1.2.1 Var, const and let


In ES6, there are 3 keywords to declare variables with. We will get back
to this later when we talk about hoisting, but it’s important to know the
basic differences for now:

var​: ​If it’s not declared inside a function, that variable is accessible
anywhere in your code. If it’s declared inside a function, it’s accessible
anywhere in that function.
let​:​ ​Is only accessible in the block you’ve declared it in.
const​: ​Works the same as var, but its value can’t be reassigned.

5
1.2.2 Coercion
Converting a value from one type to another. This is possible because
JavaScript is dynamically typed. Example:

let​ number = ​Five!'​;


number = ​5​;
// "Dangerous" example:
let​ a = ​1​ + ​'2'​;
console​.log(a); ​// "12"
The first parameter was coerced into a string, which was then
concatenated​ (joined) with the second string. Together, they made ​"12"​,
which was logged in the console. If there’s a lot of code, you might not
notice that one parameter’s value was coerced into another type.

1.3 Operators

Operators are ​special functions​ in JavaScript. “Under the hood” (how


the syntax parser interprets it), operators are functions, however they’re
written in a different way.
Infix notation​: the operator is in between two parameters.
Prefix notation​: the operator is before the parameters.
Postfix notation​: the operator is behind the parameters.

1.3.1 Assignment operators


Assigns a value to its left operand based on the value of its right operand.

Name Shorthand operator Meaning

Assignment x ​=​ y x = y

Addition x ​+=​ y x = x + y

Subtraction x ​-=​ y x = x - y

Multiplication x ​*=​ y x = x * y

Division x ​/= ​y x = x / y

Remainder x ​%=​ y x = x % y

Exponentiation x ​**= ​y x = x ** y

6
1.3.2 Comparison operator
Compares its operands and returns a boolean based on whether the
comparison is true or false.

Name Notation

Equal myNum ​=​ 0

Not equal myNum ​!=​ 0

Strict equal myNum ​===​ 0

Strict not equal myNum ​!==​ 0

Greater than myNum ​>​ 0

Greater than or equal myNum ​>=​ 0

Less than myNum ​<​ 0

Less than or equal myNum ​<=​ 0

Often, if the two operands are not of the same type, JavaScript attempts
to ​convert one or both operands ​to an appropriate type in order to
compare the two. For example, ​myNum​ ​==​ ​0​ also returns true if
myNum​ ​=​ ​'0'​, or even if ​myNum​ ​=​ ​false​. ​JavaScript converts the string and
the boolean to a number in order to be able to make the comparison,
without you really knowing.

If you use ​strict equal​ or ​strict not equal​, it will really only return true if
the type of the value equals the type of the value in the comparison. So
myNum ​===​ ​0​ ​would return​ ​false​ ​if ​myNum ​=​ ​'0'​, because the type of the
operand in the comparison is a number, and not a string. It’s advised to
use​ strict equal​ and ​strict not equal​ in almost all cases.

7
1.3.3 Arithmetic operators
Takes numerical values as their operands and returns a single numerical
value.
Unary operation​: an operation with only​ one operator​.
Binary operator​: an operation that operates on two operands and
manipulates them to return a result.

Name Example Explanation

Remainder 12​ ​%​ ​5​ ​=​ ​2 Binary operator. Returns the


remainder​ of ​dividing​ the two
operands.
5​ ​*​ ​2​ = ​10​, so you have the remainder
of ​2​.
6​ ​%​ ​3​ = ​0​, because ​3*2​ is ​6​.
7​ ​%​ ​3​ = ​0​, because ​3*2​ gives us the
remainder ​1​.

Increment x​++​ ​or​ ​++​x Unary operator. ​Increments​ the


operand by ​one​.
The difference between ​x++​ and ​++x​:

x = 3​, +
​ +x​ sets ​x​ to 4 and returns​ 4
x = 3​, x​ ++​ returns​ 3​, then sets it to 4

Decrement x​--​ ​or​ ​--​x Unary operator. ​Decrements​ the


operand by ​one​. See “Increment” for
difference between ​x--​ and ​--x​.

Unary negation -​x Unary operator. Returns the negative


value of the operand.
x = 3​, ​-x​ returns​ ​-3

Unary plus +​x Unary operator. Attempts to convert


the operand to a number!

+​true​ ​// 1
+​"3"​ ​// 3

8
1.3.4. Logical operators
Logical operators often return a boolean value.

Falsy​: Values that ​evaluate​ to false. There are six falsy values:
undefined​,​ ​null​, ​NaN​, ​0​, ​""​,​ and ​false​.
These values return ​false​ if we converted them into a boolean.
Truthy​: Values that evaluate to true. The easiest way of knowing
whether it would be truthy, is by checking if it wouldn’t be falsy.

0 = falsy, however ​new​ ​Number​(0)​ is truthy.


false = falsy, however ​new​ ​Boolean​(​false​)​ is truthy.

Name Usage Definition

And expr1​ ​&&​ expr2 Returns ​true​ if both expressions return ​true​.
With non-boolean values, it will return the
right operand if both values are truthy.

Or expr1​ ​|| ​expr2 Returns ​true​ if one of the expressions


returns ​true​. With non-boolean values, it will
return the left operand if both values are
truthy.

Not !​expr If it’s operand can be converted to true, it


will return false.
!​true​ is ​false​.
!​false​ ​is ​true​.
!​'Cat'​ is ​false​ (because ​'Cat'​ is truthy)

1.3.5 Operator precedence and associativity


Operator precedence: ​which operator gets called first.
Associativity​: in what orders the operators get called. Either left-to-right
or right-to-left. This only happens if all operators have the same
precedence.

Precedence Operator Type Associativity Operator

20 Grouping n/a (…)

19 Member access left-to-right … . ...

Computed Member Access left-to-right … [...]

9
new (with arguments) n/a new … (...)

Function call left-to-right … (...)

18 new (without arguments) right-to-left new ...

17 Postfix n/a … ++
Increment/Decrement … --

16 Logical NOT right-to-left !…

Bitwise NOT ~ ...

Unary Plus +…

Unary Negation -…

Prefix Increment ++ ...

Prefix Decrement -- ...

typeof typeof ...

void void ...

delete delete ...

await await ...

15 Exponentiation right-to-left … ** ...

14 Multiplication left-to-right …*…

Division …/…

Remainder …%…

13 Addition left-to-right …+…

Subtraction …-…

12 Bitwise (Unsigned) left-to-right … << …


Left/Right Shift … >> …
… >>> …

11 Less Than left-to-right …<…

Less Than Or Equal … <= ...

Greater Than …>…

Greater Than Or Equal … >= …

in … in …

instanceof … instanceof …

10 Equality left-to-right … == …

Inequality … != …

Strict Equality … === …

Strict Inequality … !== …

10
9 Bitwise AND left-to-right …&…

8 Bitwise XOR left-to-right …^…

7 Bitwise OR left-to-right …|…

6 Logical AND left-to-right … && …

5 Logical OR left-to-right … || …

4 Conditional right-to-left …?…:…

3 Assignment right-to-left … =…
… += …
… -= …
… **= …
… *= …
… /= …
… %= …
… <<= …
… >>= …
… >>>= …
… &= …
… ^= …
… |= …

2 yield right-to-left yield …

yield* yield* …

1 Comma/Sequence left-to-right …,…

Operators with higher precedence become the operands of operators with


lower precedence.
The ​typeof​ operator returns a string with the type of the operand.
The​ instanceof​ operator checks whether the object is an instance of the
specified type, we’ll get back to this when we talk about prototypes.

1.4. Conditionals
In your code, you sometimes have to make decisions. The simplest way
of doing so is with if-else statements.

1.4.1 If-else statements


The basic syntax of an if-else statement is pretty straightforward. If the
condition between the parentheses returns true, the code after the if
statement will be executed. However, if it returned false, the code in the
else statement will be executed.
if​ (condition) {
​// Run the code that I've written here if the conditional returns true!
} ​else​ {
​// Oh no, the condition didn't return true! Run this code instead!
}

11
let​ myAge = ​19​;
if​ (myAge >= ​18​) {
​console​.log(​"I am older than 18!"​);
} ​else​ ​if​ (myAge > ​5​ && myAge < ​10​) {
​console​.log(​"I am older than 5 and younger than 10!"​);
} ​else​ {
​console​.log(​"I am older than 5 and younger than 10!"​);
}

This if-statement will log​ ​"I am older than 18!"​ in the console, as
myAge >=​ ​18​ returns ​true​.

1.4.2 Conditional operator

let​ myVar = ​condition​ ​?​ val1 ​:​ val2

If condition returns​ ​true​, the variable has the value of ​val​. Otherwise, it
has the value of ​val2​. You can read the ​?​ as the question ​“Did the
condition just return true?”​ If that question gets answered with ​“yes”​, the
first value will be returned, which is ​val1​ in this case. The ​:​ can be read
as the ​“else”​, so if the condition returned​ ​false​. If that’s the case, then
val2​ will be returned. Example:

let​ myAge = ​19​;


let​ status = (myAge >= ​18​) ​?​ ​'adult'​ ​:​ ​'minor'​;
// The value of status is adult, because myAge is bigger than 18, so the
condition returned true.

12
1.4.3 Switch statements
If you have many conditions, it might be annoying to always write the
else​ statement. In that case, you will use switch statements. Example:

switch​ (​expression​) {
​case​ choice1:
​// Your code here.
​break​;

​case​ choice2:
​// Your code here.
​break​;

​case​ choice3:
​// Your code here.
​break​;

​default​:
​// Hmm none of the cases turned out to be true, just run this.
}

Note the colon after the case, the semicolon after break and no break
after default. ​Don’t use switch cases if you need comparisons​.

WRONG ​ RIGHT
switch​ (age) { switch​ (age) {
​case​ (age < ​18​): ​case​ ​18​:
​console​.log(​"Kiddo."​); ​console​.log(​"You're 18"​);
​break​; ​break​;
​case​ (age >= ​18​): ​case​ ​19​:
​console​.log(​"Adult."​); ​console​.log(​"You're 19"​);
​break​; ​break​;
} }

Use​ if-else​ in that case.

13
1.5 Arrays

An array is a special type of object used to store ​a sequence of data​.

const ​myArray = [​4​, ​12​, ​1​];

You can refer to an ​element​ in the array by using its ​index​. In


JavaScript, we start to count at 0. The first element in the array, in our
case ​4​, has the index 0. Our second element, in our case ​12​ ​has the index
1, etc. You can get the item by typing ​arrayName[index]​.

console​.log(myArray[​0​]) /
​ / 4
console​.log(myArray[​1​]) /​ / 12
console​.log(myArray[​2​]) / ​ / 1

You can get the length of an array by typing ​arrayName.length​, in our


case ​myArray.length​ which returns​ 3. ​We can also add items to our array
by using​ .push.

let​ myArray = [​4​, ​12​, ​1​];


let​ total = myArray.push(​5​);

console​.log(myArray) ​// [4, 12, 1, 5]


console​.log(total) ​// 4 (the length of the new array).

.push ​is just one of many built-in methods, to see more go to ​Methods​.

1.6 Objects

An object is a collection of ​related data​. For example:


let​ person = {
name: [​"Lydia"​, ​"Hallie"​],
age: ​19​,
gender: ​"female"​,
interests: [​"yoga"​, ​"programming"​, ​"petting dogs"​],
};

14
Our person object has multiple ​members​, in our case do the members
have the ​key​ of ​name​, ​age​, ​gender​ and​ interest​, and the ​value​ of [
​ ​"Lydia"​,
"Hallie"​]​, ​19​, ​"female"​ and ​[​"yoga"​, ​"programming"​, ​"petting dogs"​]​. Each
pair is called a ​key/value pair​. There are two ways of accessing object
members.

1.6.1 Dot Notation

objectName.keyName = value

person.age = ​19​;
person.interests = [​"yoga"​, ​"programming"​, ​"petting dogs"​];

You can also ​add ​key/value pairs this way:


person.birthday = ​"1998/06/04"​;

1.6.2 Bracket Notation

objectName["keyName"] = value

person[​"age"​] = ​19​;
person[​"interests"​] = [​"yoga"​, ​"programming"​, ​"petting dogs"​];

1.6.3 Dot Notation vs. Bracket Notation


In JavaScript, ​all object keys are strings​. Even though we might not
type​ them as a string, they are always converted into strings under the
hood. This might lead to issues when using the dot notation, example:

let​ x = ​"age"
/* We declared a variable with the value age, which is already
a key on our object. We would expect that person.x is actually
person.age, and person[x] is person["age"]. */

person.x returns ​undefined


person[x] returns ​19

15
person.x​ returned ​undefined​, because JavaScript started looking for a key
that was called ​"x"​ ​(a string, because object keys are strings), rather
than the value of the variable. We didn’t have a key/value pair with a key
called ​"x"​, so ​person.x​ returned ​undefined​. ​Dot notation only lets you
access the explicit key name of a property.

person[x] ​returned ​19​, because JavaScript interprets (or ​unboxes​)


statements. It sees the first opening bracket ​[​, and keeps on going until it
finds the closing bracket ]. Only then, it will evaluate the statement.

let​ bird = {
feathers: ​"colorful"​,
size: ​"small"​,
}

let​ mouse = {
name: ​"cute tiny mouse"​,
small: ​true​,
}

mouse[​"small"​] = ​true​;

"Small"​ is also the value of ​bird.size​, or​ ​bird[​"size"​]​. What happens if


we write that instead of small?

console.log(mouse.bird.size)
// TypeError: Cannot read property 'size' of undefined.
console.log(mouse[bird[​"size"​]])
// ​true

mouse.bird.size​ returned an error, as ​bird​ isn’t a key on the ​mouse


object, so it returned ​undefined​.​ It can’t find the ​size ​property on
undefined​.

16
1.6.4 Object methods
There are many different methods you can use in order to get,
manipulate, or delete data from objects. These are the most common:

let​ myObj = {
firstName: ​"John"​,
lastName: ​"Doe"​,
gender: ​"male"​,
}

Object​.entries(myObj)[​0​] ​// ["firstName", "John"]


Object​.keys(myObj) ​// ["firstName", "lastName", "gender"]
Object​.values(myObj) ​// ["John", "Doe", "male"]
Object​.assign(myObj, {age: ​50​})
// { firstName: "John", lastName: "Doe", gender: "male", age: 50 }
delete​ ​myObj.firstName​ // true
=> ​console​.log(myObj)​ // { lastName: "Doe", gender: "male" }

17
1.7 Functions

If you want JavaScript to do a particular task, you use functions. A


function is executed when you ​invoke​ it.

function​ ​sayMyName​() {
​console​.log(​"Your name is Lydia"​);
}

sayMyName(); ​// "Your name is Lydia"


// We are invoking the function, using the function name and the
parentheses.

Between the parentheses, you can include arguments (also called


parameters).

function​ ​whatsMyAge​(age) {
​console​.log(​`Your age is ​$​{​age​}`​);
}
whatsMyAge(​19​); ​// Your age is 19.
whatsMyAge(​7​); ​// Your age is 7.
whatsMyAge(​31​); ​// Your age is 31.

// During the first invocation, 19 is our parameter, which we can


pass to the function because we allowed it to receive a parameter
by having “age” between the parentheses in the function.

18
1.7.1 Function expressions
We can also assign a variable. There are ​anonymous function
expressions​ and ​named function expressions​. Anonymous functions
don’t have an identifier to refer to the function. You normally use
anonymous functions as a parameter to other functions. That’s important
to remember when we get to ​Callbacks ​and ​Hoisting.

Anonymous Named
var​ dog = ​function​() { var​ dog = ​function​ ​bark​() {
​console​.log(​'Bark!'​); ​console​.log(​'Bark!'​);
} }

dog(); ​// Bark! dog(); ​// Bark!

1.7.2 Function statements


A function statement declares a function.
function​ ​sayHi​() {
​console​.log(​'Hi'​);
}

sayHi(); ​// Hi

You “save” the function, to be invoked later. Function statements get


hoisted​, which means you always have access to them, even before
declaring the function. We could’ve typed ​sayHi()​ on lines above the
actual (global!) function, and it would have worked.

1.7.3 Arrow functions


Since ES2015, we can use a shorter function syntax called an arrow
function. There are some differences between arrow functions and regular
functions, regarding the ​this​ ​keyword.

const​ sayHi = () => {


​console​.log(​'Hi'​);
}

sayHi(); ​// Hi

19
Arrow functions are a lot smaller and can be inline. It saves a lot of space,
compared to the regular functions.

const​ materials = [​'Hydrogen'​, ​'Helium'​, ​'Oxygen'​, ​'Lithium'​];


// Old function syntax:
materials.map(​function​() {
​return​ material.length;
})
// Arrow function syntax
materials.map(material => material.length);

If you write curly brackets, you have to write return. However, by using
the normal parentheses or none at all, you don’t. You can only do this if
you just return one value! With arrow functions,​ this​ ​refers to its ​current
surrounding scope​, unlike regular functions! We will get back to this when
we talk about the keyword ​this​.

PARENTHESES EXAMPLE this​ ​EXAMPLE


const​ add = x => { let​ person = {
​return​ x * x name: ​"Lydia"​,
} hobbies: [​"yoga"​, ​"coding"​],
// "​ ​Better​"​ syntax getHobbies() {
const​ add = x => (x * x); ​return​ ​this​.hobbies.map(hobby => (
​`​$​{​this​.name​} likes ​$​{​hobby​}`
));
}
}
person.getHobbies()​;​ // ["Lydia likes yoga",
"Lydia likes coding"]

20
1.7.4 IIFE
IIFE stands for​ Immediately-Invoked Function Expression​. Right
after creating the function, we invoke it.

(​name​ => {
​console​.log(​`Hey ​$​{​name​}`​)
})(​'Lydia'​); ​// "Hey Lydia"

We wrap the function within parentheses, and right after closing the
parentheses we invoke it how we usually invoke functions. This is very
useful when we want to invoke anonymous functions!

1.7.5 Callback Functions


When a function receives another function as an argument, that received
function is a ​callback function​. Example:
const m​ ultiply​ ​=​ ​(​a​, ​b​) => ​a​ * ​b​;
const​ a​ dd​ ​=​ ​(​a​, ​b​)​ ​=> ​a​ + ​b​;
const​ d ​ ivide =​ ​(​a​,​ ​b​)​ ​=> ​a​ / ​b​;

const ​mySum =​ ​(x, y, fn) => ​fn(x, y)​;

mySum(4, 5, multiply); ​// 20


mySum(4, 5, add);​ // 9
mySum(4, 5, divide); ​// 0.8

The callback function is not run until the containing function invokes it, or
“​calls it back​”​. Once the containing function has stopped running, it calls
back to the function that was passed in the parameter, hence the name
callback function. This example is a synchronous callback, the callback
function is being run where we invoke it. However, often callback
functions are being executed ​after​ an asynchronous function has
completed.

1.7.6 Promises
Now, imagine that that callback function contained another callback
function, then that callback function had another callback function. This
would lead to very chaotic code! To avoid that, we use promises. ​With
promises, we can postpone the execution of a code block until an

21
asynchronous operation is completed. This way, other operations can
keep running without interruption.
A promise may complete at some point and produce a value. Once that
value is ready, it allows you to do something with that value.

Promises have three states:


1. Pending​: the initial state of the promise
2. Fulfilled​: the specified operation was completed.
3. Rejected​: the operation did not complete.

Promises look very much like promises in real life. You promise to walk
the dog, after you’ve done a certain task. However, promising something
doesn’t guarantee that you actually do it! You write a promise this way:

let​ promiseToWalkDog = ​new​ ​Promise​((resolve, reject) => {


​// walk the dog
​let​ hasWalkedDog = ​true​;
​if​ (hasWalkedDog) {
resolve(​'I did it!'​);
} ​else​ {
reject(​'I didn\'t do it..'​);
}
})

promiseToWalkDog.then((fromResolve) => {
console.log(​`Did you walk the dog? ​$​{​fromResolve​}`​);
}).catch((fromReject) => {
console.log(​`Did you walk the dog? ​$​{​fromReject​}`​);
});

Only when the promise is resolved, the ​.then​ method will be fired. If the
promise rejected, the ​.catch​ method will be fired. Within that method you
can have a callback function. From ​resolve([argument])​, we pass that
argument to the f​romResolve([receives that argument here])​ function.
The ​.catch​ handles the reject function.

Resolve:​ it actually did what it said it would do!


Reject:​ it didn’t fulfill what it said it would do, it rejected.

22
You can also promise to clean the room after you’ve walked the dog, after
you’ve cooked food.

let​ cookFood = () => ​Promise​.resolve(​"I have cooked food"​);


let​ walkDog = () => ​Promise​.resolve(​"I have walked the dog!"​);
let​ cleanRoom = () => ​Promise​.resolve(​"I have cleaned the room!"​);

cleanRoom()
.then(() => walkDog()) ​// No semicolon!
.then(() => cleanRoom()) ​// No semicolon!
.then(() => ​console​.log(​"All three promises were fulfilled!"​));
Note that we are ​only resolving​ here! This is why the syntax differs from
the first example. You can’t write a semicolon if you have another ​.then​!
You avoid nested code by using promises. If you want all three promises
to run at the same time, and once all of them are done you want to do
something. This is possible with ​Promise.all​!

Promise​.all([cookFood(), walkDog(), cleanRoom()])


.then(() => ​console​.log(​"All three promises were fulfilled!"​));

If you want just one to finish, you use ​Promise.race

1.7.7 Async/await
An async function is syntactic sugar over promises, the code looks much
cleaner. Its asynchronous code looks and behaves a little more like
synchronous code. With async/await, you really wait for one promise to
resolve before moving to the next line.

Async/await function Promise


const​ makeRequest = ​async​ () => { const​ makeRequest = () => {
​await​ callPromise() ​return​ callPromise()
​await​ callPromise() .then(() => callPromise())
​await​ callPromise() .then(() => callPromise())
} .then(() => callPromise())
}
makeRequest(); makeRequest();

23
const​ makeRequest = ​async​ () => { const​ makeRequest = () =>
​console​.log(​await​ getJSON()) getJSON()
​return​ ​"All done!" .then(data => {
} ​console​.log(data)
​return​ ​"All done!"
makeRequest() }
makeRequest();

The function has the keyword ​async​ before it. Any ​async​ function returns
a promise implicitly, and the resolve value of the promise will be whatever
you return from the function (​"All done!"​ in our case).
console​.log​(​await​ ​getJSON()​)​ basically means: wait until the ​getJSON
promise has resolved, then ​console​.log​ gets called that prints the value.
It pauses the execution of your method until the value from the promise
is available. If you don’t await, you’ll get the promise instead of the value
you expect! Async await and promises are ​not logically equivalent​!
The async/await loads the results in sequence, while the promise example
loads in parallel. Async/await and promises are the same thing under the
hood. That’s the reason why we can do stuff like this:

​ wait​ getFoo();
let​ foo = a
let​ bar = a​ wait​ getBar();

// You can write this shorter like:


let​ [foo, bar] = ​await​ ​Promise​.all([getFoo(), getBar()]);

24
1.8 Loops

1.8.1 For loops

let​ myArray = [​1​, ​2​, ​3​, ​4​];


for​ (​let​ i = ​0​; i < myArray.length; i++) {
​console​.log(myArray[i] * ​2​);
}

// 2
// 4
// 6
// 8

You can use loops if you want JavaScript to do something repeatedly. We


want to loop over our array, ​myArray​. We want to log every single item in
the array in the console, multiplied by 2.
i = ​0​; i < myArray.length; i++

Initialization expression
The first part of our for loop starts with ​i = 0​, or basically: index equals
zero. By saying ​i = 0​, you’re just saying: the loop has to start at the first
item in the array. If we said ​i=1​, the loop would’ve started at the second
item in the array. This part is called the​ initialization expression​ and
runs only once!

Conditional expression
JavaScript evaluates this expression before ​each​ loop! By writing
i < myArray.length​, you are basically saying “keep the loop going as long
as there are items in the array”. Before each and every loop, JavaScript
checks whether the conditional expression returns true or false. If it
returns true, if moves on to the third part of the loop. If it returns false,
the loop ends and JavaScript moves on to the next line of code. You can
replace the ​myArray.length​ with any value you like, f.e. ​i < 5​.

Final-expression
The third and last part of the loop increases a value each time the code
block in the loop ​has been executed​, so it moves on to the next item in
the array.

25
1.8.2. For/in loops

let​ myObj = {
a: ​15​,
b: ​3​,
c: ​14​,
};

for​ (​const​ item ​in​ myObj) {


​console​.log(myObj[item] * ​2​)
}

// 30
// 6
// 28

We want to loop over our object, and return every value multiplied by 2.
for​ (​const​ item ​in​ myObj)

A different property name is assigned to ​item​ ​on each iteration. First,


item​ ​is​ ​a​, on the second iteration, ​item​ ​is​ ​b​, and so on. ​myObj​ ​is the name
of object you’re iterating over.

1.8.3 While loops


The while statement creates a loop that executes as the condition
evaluates to true. The condition is evaluated ​before​ executing the
statement.

let​ myNumber = ​0​;


while​ (myNumber < ​10​) {
myNumber++
}
console​.log(myNumber); ​// 10

While the number has a value that’s lower than ​10​, the statement gets
executed. The statement is ​myNumber++​, which increases the value of
myNumber​ on every execution. The last number where the condition would
return true, is if ​myNumber = 9​. ​myNumber ​then gets incremented one more
time, which makes it ​10​.

26
1.8.4 Do/while loops
Creates a loop that executes the statement until the condition evaluates
to false. The condition is evaluated ​after​ executing the statement, which
means that the statement will always run at least once.

let​ myNumber = ​0​; let​ myNumber = ​0​;

do​ myNumber++ do​ myNumber++


while​ (myNumber < ​10​) while​ (myNumber < ​0​)

console​.log(myNumber); ​// 10 console​.log(myNumber); ​// 1

First, it increases the value of the variable ​myNumber​ with ​1​. Then, the
condition evaluates to false, as ​myNumber​ isn’t smaller than ​0​, which ends
the ​do..while​ loop.

1.8.5 Break and continue


The ​break​ statement can be used to​ jump out ​of a loop. If a certain
condition returns true, then stop the loop.

for​ (​let​ i = ​0​; i < ​5​; i++) {


​if​ (i === ​3​) ​break​;
​console​.log(i);
}
// 0
// 1
// 2
The ​continue​ statement ​skips​ an iteration if a certain condition returns
true.
for​ (​let​ i = ​0​; i < ​5​; i++) {
​if​ (i === ​3​) ​continue​;
​console​.log(i);
}
// 0
// 1
// 2
// 4

27
1.9 Common Methods

JavaScript has many built-in methods that you can use. You always have
access to them.

1.9.1 String methods and properties

.​charAt()

Returns the character at the specified index (position).

'Hey world!'​.charAt(1); ​// "e"

.concat()

Joins two or more strings, and returns a new joined strings.

let​ firstString = ​'I want '​;


let​ secondString = ​'pizza'​;

secondString.concat(firstString); ​// "I want pizza"

.endsWith()

Checks whether a string ends with specified string/characters.

'Hey there people'​.endsWith(​'people'​); ​// true

However, you can also change the length it looks for!

'Hey there people'​.endsWith(​'there'​, ​11​); ​// true

The final index it will look for is 11. In that case, the string indeed ends at
there​ so it returns true!

28
.​includes()
Checks whether a string contains the specified string/characters. It is case
sensitive!

let​ myString = ​'There is a small, cute dog here'​;


myString.includes(​'small'​); ​// true
myString.includes(​'SMALL'​); ​// false

.indexOf()
Returns the position of the first found occurrence of a specified value in a
string.

let​ myString = ​'Dogs are just amazing'​;


myString.indexOf(​'are'​); ​// 5
myString.indexOf(​'ama'​); ​// 14

.lastIndexOf()
Returns the index of the last found occurrence of a specified value in a
string.

'How many cookies could a good cook cook?'​.lastIndexOf(​'cook'​);


// 35

.​repeat()
Returns a new string with a specified number of copies of an existing
string.

'I need coffee! '​.repeat(​2​);


// "I need coffee! I need coffee!"

.​replace()
Searches a string for a specified value, or a regular expression, and
returns a new string where the specified values are replaced.

'I need coffee!'​.replace(​'coffee'​, ​'tea'​);


// "I need tea!"

29
.slice()
Extracts a part of a string and returns a new string. The first argument is
the first index of the new, sliced array, the second argument is the last
index which is excluded.

'Hello World'​.slice(​1​, ​5​);


// "ello"

.split()
Splits a string into an array of substrings.

'How are you today?'​.split(​' '​);


// ["How", "are", "you", "today?"]

.startsWith()
Checks whether a string begins with specified characters.

let​ myString = ​'​My favorite color is pink​'​;


myString.startsWith(​'​My​'​); ​// true
myString.startsWith(​'​Hello​'​); ​// false
myString.startsWith(​'​favorite​'​, 3)); ​// true

.substr()
Extracts the characters from a string, beginning at a specified start
position, and through the specified number of character.

'Hello world'​.substr(​1​, ​4​);


// "ello"

The 1
​ ​is the index to start, the ​4​ is the ​total length​, not the final index.
The difference between this and ​.slice()​ is the answers you’ll get when
you don’t fill in anything, such as NaN or undefined etc.
myString.substr(​-1​) ​// "d". Using Internet Explorer: "Hello World"

!!​ IE returns the whole string if the argument is negative.

30
.substring()
Extracts the characters from a string, between two specified indices. The
second parameter is the end index.

'Hello world'​.substring(​1​, ​4​);


​// "ello"

.toLowerCase()
Converts a string to lowercase letters.

'WHY AM I SHOUTING?!'​.​toLowerCase();
// "why am i shouting?!"

.toString()
Returns the value of a string.

'Coding is fun'​.toString();
// "Coding is fun"

.toUpperCase()
Converts a string to uppercase letters.

'I am whispering'​.toUpperCase();
// "I AM WHISPERING"

.trim()
Removes whitespace from both ends of a string.

' Hello there! '​.trim();


// "Hello there!"

31
1.9.2 Array methods and properties

.concat()
Joins two or more arrays, and returns a copy of the joined arrays.

let​ a = [​1​, 2
​ ​, 3​ ​];
let​ b = [​4​, 5​ ​, 6​ ​];
a.concat(b) / ​ / [1, 2, 3, 4, 5, 6];

.every()
Checks if every element in an array pass a test.

const​ testValue = (element) => element > ​10​;

​ 5​, 7
[​14​, 1 ​ ​, ​90​].every(testValue); / ​ / false
[​13​, 8​ 0​, 3​ 0​, ​20​].every(testValue); /​ / true

.fill()
Fill the elements in an array with a static value.

[​1​, ​2​, ​3​].fill(​3​); ​// [3, 3, 3]

.​filter()
Creates a new array with every element in an array that passes a test.

const​ isBigEnough = (value) => value >= ​10​;

let​ myArray = [​1​, ​2​, ​90​, ​20​, ​19​, ​30​];


let​ myFilteredArray = myArray​.filter​(isBigEnough);
console​.log(myFilteredArray); ​// [90, 20, 19, 30]

32
.find()
Returns the value of the first element in an array that passes a test.

const​ isBigEnough = (value) => value >= ​10

let​ myArray = [​1​, ​2​, ​90​, ​20​, ​19​, ​30​];


let​ item = myArray​.find​(isBigEnough);
console​.log(item); ​// 90

.findIndex()
Returns the index of the first element in an array that passes a test.

const​ isBigEnough = (value) => value >= ​10

let​ myArray = [​1​, ​2​, ​90​, ​20​, ​19​, ​30​];


let​ item = myArray​.findIndex​(isBigEnough);
console​.log(item); ​// 2

.forEach()
Calls a function for each array element.

let​ array = [​1​, ​2​, ​3​];


array.forEach(element => ​console​.log(element * ​2​));

// 2
// 4
// 6

.​indexOf()
Search the array for an element and returns its position

[​"blue"​, ​"green"​, ​"yellow"​].indexOf(​"green"​) ​// 1

33
.isArray()
Checks whether the passed parameter to the ​Array.isArray​ function is an
array.

Array​.isArray([​1​]); ​// true


Array​.isArray(); ​// false
Array​.isArray(​true​); ​// false

.join()
Joins all elements of an array into a string

[​1​, 2
​ ​, 3​ ​].join(​''​); ​// "123"
[​1​, 2​ ​, 3​ ​].join(); ​// "1,2,3"

.​lastIndexOf()
Search the array for an element, starting at the end, and returns its
position.

[​2​, ​5​, ​9​, ​2​].lastIndexOf(​2​); ​// 3

.​map()
Creates a new array with the result of calling a function for each array
element

const​ myNumbers = [​2​, ​3​, ​4​];


const​ doubles = myNumbers.map(x => x * ​2​);
console​.log(doubles) ​// [4, 6, 8];

34
.pop()
Removes the last element of an array, and returns that element. It
modifies the original array!

const​ numbers = [​1​, ​4​, ​2​, ​0​, ​9​, ​1​];


const​ lastNumber = numbers.pop();
console​.log(numbers); ​// [1, 4, 2, 0, 9];
console​.log(lastNumber); ​// 1

.​push()
Adds new elements to the end of an array, and returns the new​ length. ​If
you define a variable with the .push method, the ​length​ will be returned.

let​ numbers = [​2​, ​3​, ​1​, ​2​, ​3​];


let​ newNumbers = numbers.push(​4​);

console​.log(numbers); ​// [2, 3, 1, 2, 3, 4];


console​.log(newNumbers); ​// 6

.reduce()
Reduce the values of an array to a single value (going left-to-right).

let​ numbers = [​11​, ​50​, ​39​, ​20​];


let​ sum = numbers.reduce((cur, acc) => cur + acc) ;

console​.log(sum); ​// 120

It takes the first item first, which is ​11​ ​in this case. It goes over​ ​11​, ​so now
11​ ​is the current value​ ​cur​.​ Then it goes to ​50​, ​which is now​ ​acc​. ​The
function says​ cur + acc​, ​so what will happen is it will return ​11​ + ​50​,
which is ​61​. ​61​ ​is now the current value ​cur​, ​so now ​39​ ​is​ ​acc​, ​and so on.

.​reverse()
Reverses the order of the elements in an array.

[​1​, ​2​, ​3​, ​4​].reverse(); ​// [4, 3, 2, 1]

35
.shift()
Removes the first element of an array, and returns that element.

let​ numbers = [​2​, ​3​, ​1​, ​2​, ​3​];


let​ firstNumber = numbers.shift();
console​.log(numbers); ​// [3, 1, 2, 3, 4];
console​.log(firstNumber); ​// 2

.slice()
Selects a part of an array, and returns the new array. The original array
doesn’t get modified.

let​ numbers = [​2​, ​3​, ​1​, ​2​, ​3​];


let​ newNumbers = numbers.slice(​1​, ​3​);

console​.log(numbers); ​// [3, 1, 2, 3, 4];


console​.log(newNumbers); ​// [3, 1]

The slice function ​excludes the item with index of the second
parameter​! So when you write ​.slice(1,3)​, it actually only “slices” the
second and third item, not the fourth.

.​some()
Checks if any of the elements in an array passes a test.

const​ testValue = (element) => element > ​10​;

[​1​, 5
​ ​, 7​ ​, 9​ ​].some(testValue); / ​ / false
[​1​, 5​ ​, 7​ ​, 1​ 1​].some(testValue); /​ / true

.sort()
Sorts the elements of an array.

[1, 4, 3, 4, 2, 3].sort(); ​// [1, 2, 3, 3, 4, 4]


[​"bear"​, ​"zebra"​, ​"horse"​].sort(); ​// ["bear", "horse", "zebra"]

36
.splice()
Adds/Removes elements from an array.

let​ colors = [​"red"​, ​"yellow"​, ​"green"​]


colors.splice(​2​, ​0​, ​"purple"​);
console​.log(colors) ​// ["red", "yellow", "purple", "green"]

The​ ​2​ ​stands for the position on which you want to start adding items.​ ​The
0​ ​stands for how many items you want to have removed, in this case ​0​.
What if we changed the​ ​2​ ​to a​ ​1​ ​and the​ ​0​ ​to a​ ​1​?

let​ colors = [​"red"​, ​"yellow"​, "​ green"​]


colors.splice(​1​, ​1​, ​"purple"​); /​ / "yellow"
console​.log(colors) ​// ["red", "purple", "green"]

.​toString()
Converts an array to a string, and returns the result.

[​"Dog"​, ​"Cat"​, ​"Donkey"​].toString(); ​// "Dog,Cat,Donkey"

.unshift()
Adds new elements to the beginning of an array, and returns the new
length.

let​ numbers = [​3​, ​4​, ​5​]


let​ newLength = numbers.unshift(​1​, ​2​);
console​.log(numbers); ​// [1, 2, 3, 4, 5]
console​.log(newLength); ​// 5

.​valueOf()
Returns the primitive value of the array.

[​"red"​, ​"green"​].valueOf();​ ​// ["red", "green"]

37
1.9.3 Math Object
The math object allows you to do mathematical calculations on numbers.

Math.round()
Returns the passed value down or up to its nearest integer.

​ / 3
Math​.round(​3.4​); /
Math​.round(​3.5​); /​ / 4
Math​.round(​3.6​); / ​ / 4

Math.pow()
Returns the first passed value to the power of the second passed value.

Math​.pow(​10​, ​2​) ​// 100

Math.sqrt()
Returns the square root of the passed value.

Math​.sqrt(​64​); ​// 8

Math.abs()
Returns the absolute (positive) value of the passed value.

Math​.abs(​-2.3​) ​// 2.3

Math.ceil()
Returns the passed value ​up​ to its nearest integer.

​ / -4
Math​.ceil(-​4.3​); /
Math​.ceil(​4.01​); /​ / 5

38
Math.floor()
Returns the passed value ​down​ to its nearest integer.

Math​.floor(​4.7​); ​// 4
Math​.floor(​-4.3​); ​// -5

Math.min() and Math.max()


Find the lowest value in a list of arguments with Math.min(), and the
highest with Math.max()

​ ​, 3
Math​.min(​400​, 2 ​ ​, 1​ ​, 2​ 0​, 3​ 0​); /​ / 1
Math​.max(​400​, 2​ ​, 3​ ​, 1​ ​, 2​ 0​, 3​ 0​); /​ / 400

Math.random()
Returns a random value.

​ / returns a random value between 0 and 1


Math​.random() /
Math​.random() * ​100​ ​// returns a random value between 0 and 100

39
1.10 DOM Manipulation

JavaScript can:
● change, create and remove HTML elements + attributes.
● change all the CSS styles in the page.
● respond to all existing HTML events in the page.

In order to do so, you manipulate the Document Object Model (DOM). The
DOM is created when the webpage is loaded. The ​document​, which is
accessible in the window object, is the root node (the element that’s on
top of the tree), and has access to all other ​nodes​ (HTML Elements).

We have a super simple website that just has a title in the head, and only
a link in the body. All elements are defined as ​objects​.

40
1.10.1. DOM Methods and Properties
By using​ ​a​ m
​ ethod​, you can manipulate the content of the HTML
elements.
By using a p ​ roperty​, you can access the property of HTML elements.

document.getElementById(​"id"​)
R​eturns an element object representing the element whose ​id​ matches
the string.

<p​ id=​"test"​>​</p>

const​ test = ​document​.getElementById(​"test"​)

document.getElementsByClassName(​"​class​"​)
R​eturns a node list representing the element whose class name matches
the string.

​ lass​=​"info-button"​>​Information 1​</button>
<button​ c
<button​ c​ lass​=​"info-button"​>​Information 2​</button>
<button c ​ lass​=​"info-button"​>​Information 3​</button>

const​ buttons = ​document​.getElementsByClassName(​"info-button"​)

document.createElement(​"​tagname​"​)
Creates the HTML element specified by its tagname. Tag names are for
example ​div​, ​p​, ​h1​, ​a​, etc.

​ ocument​.createElement(​"div"​);
let​ newDiv = d
let​ newTitle = ​document​.createElement(​"h1"​);

41
document.querySelector(​"​#id​"​, ​"​.class​"​ or ​"​element​"​)
Returns the ​first​ element within the document that matches the specified
selector, or group of selectors.

<button​ ​id​=​"info"​>​Information 1​</button>


<button​ ​class​=​"info-button"​>​Information 2​</button>
<button>​Information 3​</button>

const​ firstButton = ​document​.querySelector(​"#info"​)


const​ secondButton = ​document​.querySelector(​".info-button"​)
const​ thirdButton = ​document​.querySelector(​"button"​)

parentNode.appendChild(node)
Appends a node as the last child of a node. For example, if we want to create
a div with a paragraph in it.

let​ newDiv = ​document​.createElement(​"div"​); ​// <div></div>


let​ newParagraph = ​document​.createElement(​"p"​); ​// <p></p>

newDiv.appendChild(newParagraph); ​// <div><p></p></div>

You add text to the paragraph by using ​document.createTextNode.

let​ newText = ​document​.createTextNode(​"This is my new text!"​);


newParagraph.appendChild(newText);
// <p>This is my new text!</p>
newDiv.appendChild(newParagraph);
// <div><p>This is my new text!</p></div>

element.setAttribute(attributeName, value)
attributeName​: name of the attribute (href, id, class, etc.)
value​: value of the attribute

let​ p = ​document​.querySelector(​"p"​);
p.setAttribute(​"class"​, ​"greeting"​)
// Now p has the class name "greeting"

42
element.innerHTML (not recommended)
Sets or gets the HTML syntax. Setting the innerHTML has ​security risks​.
Instead, you should always try to use ​node.textContent ​if you’re only
adding a text​.

<p ​id=​"greeting"​>​</p>
--
document​.getElementById(​"greeting"​).innerHTML = ​"Hey there!"

element.getAttribute(attributeName)
Get the value of the specified attribute.

<p​ id=​"first"​ ​class​=​"greeting"​>​Hey world!​</p>


---
let​ p = ​document​.querySelector(​"p"​);
p.getAttribute(​"class"​); ​// returns greeting
p.getAttribute(​"id"​); ​// returns first

element.addEventListener(event, function, useCapture)


event: ​A string that specifies the name of the event. (Required)
function​: Specifies what to run when the event occurs. (Required)
useCapture: ​Whether the event handler should be executed in the
capturing or bubbling phase (​See ​Bubbling and Capturing)​. (Optional)
​true​: executed in ​capturing​ phase,
​false​(default): executed in ​bubbling​ phase.

<span className=​"clickable"​>Click me!​</span>


let​ span = ​document​.querySelector(​"span"​);
span.addEventListener(​"click"​, () => ​console​.log(​"click"​));

Every time you click on the span element, ​"click"​will be logged to the
console. There are many different events that can be used instead of
"click"​, which are easy to find online.

43
1.10.2 Bubbling and Capturing

Bubbling
Let’s say we have this code:

<div​ onclick=​"console.log('div')"​>
​<p ​onclick=​"console.log('p')"​>​Click here!!​</p>
</div>

A click on the ​<p>​ first runs onclick event listener on that ​<p>​, but also on
the ​<div>​. If we click ​p​, we see 2 logs: 1. ​“​p​“​, 2. ​“​div​“​. This is called
bubbling​, because events ​“​bubble​“​ up through their parent elements like
a bubble in water. The deepest nested element that caused the event is
the ​target​ of the event, the ​event.target​. You can stop bubbling by
adding ​event.stopPropagation(). ​This would be useful if you have, for
example, a button inside a button. If you click on the inner button, you
don’t want the parent node (the outer button) to receive the event as
well.

<div​ onclick=​"console.log('div')"​>
​<p ​onclick=​"event.stopPropagation()"​>​Stop!​</p>
</div>

Now when we click on our <p>, no event handler will be executed.

Capturing
The DOM event describes 3 phases of event
propagation:

1. C
​ apturing phase
2. T​ arget phase
3. B ​ ubbling phase

During the capturing phase, the event goes


through the ancestor elements ​down​ to
the target element. It then reaches the
target element, and then bubbling begins.

44
<form>
​<div>
​<p>​Click​</p>
​</div>
</form>
----
for ​(​let​ ​el​ ​of​ document.​querySelectorAll​('​*​')) {
​el​.addEventListener(​"click"​, e => alert(${​el​.tagName​}), ​true​);
​el​.addEventListener(​"click"​, e => alert(${​el​.tagName​});
}

The alert messages give us:


HTML > BODY > FORM > DIV >​ ​P​ ​> DIV > FORM > BODY > HTML
​ APTURING PHASE
C TARGET BUBBLING PHASE

Capturing is rarely used anymore as attributes such as ​onclick​ or event


listeners only go to the 2nd and 3rd phase, unless requested otherwise in
the 3rd argument (set useCapture to ​true​).

1.10.3. Prevent default


Many events already have a certain action connected to them, such as
clicking on a link or pressing the down arrow. If you don’t want this
default behavior to happen, you add ​event.preventDefault()​. If we now
click on a link, it won’t automatically take us to the URL.

45
Understanding JavaScript

2.1 Syntax Parser


Your computer can’t read JavaScript code. ​When you run JavaScript code,
a compiler converts your code into a set of instructions that machines can
understand. The ​syntax parser​ is part of this compiler. It goes through
your code character by character, and determines if the syntax is valid
JavaScript or not before executing your code. A ​JIT compiler
(Just-In-Time compiler) compiles the code ​as it’s being run, ​like the
famous V8 engine from Google used in Chrome.

2.2 Creation phase


The​ syntax parser​ wraps the executable code into an ​execution
context​. The execution context is an ​abstract ​concept of the environment
in which code is being run: either the default ​global environment​, or a
function environment​. The base execution context is the ​global
execution context​, that what’s accessible to everything everywhere in
your code. The JavaScript global execution context creates two things for
you: the ​global object ​and a​ ​special variable called ​this.

2.2.1 The ​this​ keyword


What ​this​ refers to, depends on how the function is called, however it
always refers to an object. When you’re calling this outside any function
in a browser, or if you’re calling it from a function defined in the global
context, ​this​ refers to the global object. However, if you use it in an
object, ​this​ refers to the enclosing object. ​Note the arrow function​! We
get back to the ​this​ keyword later.
var​ a = ​0​;
var​ obj = {
a: ​1​,
normalFunc: ​function​() { ​console​.log(​this​.a) },
arrowFunc: () => ​console​.log(​this​.a),
}

console​.log(​this​.a) ​// 0
console​.log(obj.normalFunc()); ​// 1
console​.log(obj.arrowFunc()); ​// 0

46
2.3 Lexical Environment

The ​lexical environment​ refers to where something sits ​physically​ in


your code, where you have actually written certain variables and
functions. The official explanation in the ES5 docs states “the association
of identifiers to specific variables and functions based upon the lexical
nesting structure of ECMAScript code”.

Association of identifiers​: the binding of variables and functions with their


values.
Lexical structure​: where the actual code was written.

const​ myFunction = () => {


​let​ a = ​"Hello world!";
}

Variable ​a​ sits lexically inside the ​myFunction​ function.

2.4 Creation and hoisting

b();
console​.log(a);

let​ a = ​"Hey"​;
function​ ​b​() {
​console​.log(​"Hey world!"​);
}

Notice how we invoke ​b​ before creating the function, and want to log ​a​ to
the console before declaring the variable. With other languages, you’d get
an error, but not with JavaScript. Instead, you get this result:

"Hey world!"
undefined

47
It runs the function, and shows that the value of variable ​a​ is undefined.
Variables and functions are available, even if they’re written later in the
code. This can happen, because during the ​creation phase​ of the code,
memory space is set up for variables and functions. This is called
hoisting​. Before your code gets executed, the JavaScript engine already
has all the variables and functions in its memory, which is why you can
call them. However, ​variables​ are stored with the default value of
undefined​, until you actually define them in your code. This is why you
get the value of undefined returned if you use a variable in your code
before defining it. Undefined does not mean not defined!

Not defined: ​I don’t have it in memory, meaning you haven’t ever


declared it in your code.
Undefined: ​I have it in memory, I see you have declared it somewhere
in your code, but you haven’t defined the variable in your code yet before
the line on which you’re trying to access it.

It is important to know the two phases:

1) Creation phase​. Global object, ​this,​ outer environment, memory.


2) Code execution. ​Runs the code line by line. Interprets the
JavaScript code, converts it to something the computer
understands, compiles that, then executes that code.

JavaScript is single threaded, meaning that it can run one command at a


time. However, that doesn’t happen under the hood. ​Synchronous​: one
at a time.

2.5 Execution stack


When you invoke a function, it gets added to the ​execution stack​. The
Global Execution Context is always
created first. No functions have been
invoked in this example. The one on
the top is the function that’s
currently running​. ​Every invoked
function creates an execution
context, and is put on top of the
stack.

48
const​ myFunc = () => ​console​.log(​"It's a function!"​);

myFunc();

When this function is called, the call stack looks like this:

When the function has finished, it gets popped off the stack. The functions
run when their stack frame is on top of the stack. A stack frame
represents a function call, and its argument data.

const ​foo = ​b => {


​let​ a = ​5​;
​return​ a * b;
}

const ​bar ​=​ ​x => {


​let​ y = ​3​;
​return​ foo(x * y);
}

console​.log(bar(​2​));

JavaScript is ​single threaded​, meaning it can only do one thing at a


time. Until now, we only saw normal functions being called, being added

49
to the call stack, and simply returning their value. However, what would
happen if we had a ​setTimeout​ function?

const​ foo = () => ​console​.log(​"First"​);


const​ bar = () => setTimeout(() => ​console​.log(​"Second"​), ​100​);
const​ baz = () => ​console​.log(​"Third"​);

bar();
foo();
baz();

// First
// Third
// Second

We have a ​setTimeout​ function and invoked it first. Yet it was logged last.
This is because in browsers, we don’t just have the runtime engine, we
also have something called a ​WebAPI​. The WebAPI gives us the
setTimeout​ method to start with, and for example the ​DOM​. You can
make calls to this. We can (sort of) do multiple things at the same time
now.

Our ​setTimeout​ function is now complete, and will be popped off the
stack. ​foo​ gets invoked.

50
The ​webAPI ​can’t just add stuff to the stack when it’s ready. Instead, it
pushes the callback function to something called a ​task queue​. This is
where an ​event loop​ starts to work.

2.5.1 Event Loop


An ​event loop​ looks at the stack and the tasks queue. If the stack is
empty, it takes the first thing on the queue and pushes it onto the stack.

This is just a simplified explanation, though it’s a crucial subject.

51
2.6 Variable scope

The variable environment (or scope) is where the variables ​“​live​“​. If a


variable is defined outside a function, it’s accessible anywhere in the
code: it’s ​global​. Local variables live inside a function, and have a
different ​scope​ on every invocation of that function. Variables defined
with the ​let​ and ​const​ keywords are not accessible outside of the block
they were defined in (a block is anything between curly brackets). The
variable identifier of ​const​ cannot be reassigned.

let​ x = ​1​;
if​ (x === ​1​) {
​let​ x = ​2​;
​console​.log(x);
}
console​.log(x);

// 2
// 1

x​ was only 2 inside that code block, so when logging ​x​ outside of the
function, it returned 1.

2.7 The scope chain

const ​b ​=​ ​() => {


​console​.log(myVar);
}

let​ myVar = ​1​;


b(); ​//1

When you do something with a variable other than declaring it, it doesn’t
just look in the variable environment. It uses the ​ref​ to the ​outer
environment​, which in function ​b​’s case is the global execution context.

52
If we had this:

function​ ​a​() {
​function​ ​b​() {
​console​.log(myVar);
}
}

let​ myVar = ​1​;


a(); ​//1

The outer environment of function ​b​ is now function ​a​. However, the outer
environment of function a is the global environment. To find the variable
myVar​, which we want to log in function ​b​, it goes down the ​scope chain​.
b​? Can’t find it. ​a​? Can’t find it. ​global​? Found it!

Scope: ​where a variable is available in your code.

A callback function gets called back after the outer function has already
finished running, and was popped off the stack. Yet, we can still access
the variables created in that function context, even though it’s been
deleted.

const​ ​someTimeout ​=​ ​() => {


​let​ a = ​"Do it now!"​;
setTimeout(() => ​console​.log(a), ​500​);
}

Even though the ​someTimeout​ function has been popped off the stack, we
still have access to variable a 500 milliseconds after. This is because of
closures​.

53
2.8 Closures

Let’s say we have this code:

const ​greet = ​greeting => (


(name) => ​console​.log(greeting + name)
)

let​ sayHi = greet(​"Hi "​);


sayHi(​"Lydia"​); ​// "Hi Lydia"

What’s going on here?

After invoking the ​greet​ function, a new​ execution context​ is created.


The ​greet​ function returns (​but doesn’t invoke​) a function. It is popped off
the stack. Then, the ​greet​ function returns and gets popped off the stack.
The execution context isn’t there anymore, yet we have access to its
variables, as every execution context has a space in memory!

54
Normally, the JS engine clears it with a process called ​garbage
collection​. The execution context of the ​greet​ function is still somewhere
in memory. We invoke the ​sayHi​ function, which creates a new execution
context. When its code is invoked, and it sees the ​sayHi​ variable, it goes
up the scope chain, and there is an ​outer lexical environment
reference​ to that variable. Although the execution context of ​sayHi​ is
gone, the execution context of ​sayHi​ still has a reference to the memory
space of its outer environment.

It is basically closing in all the variables that it should have have access
to, hence the name​ closure. ​It doesn’t matter when you invoke the
function.

55
Famous example:

const ​myFunctions = ​() => {


​let​ arr = [];
​for​ (​var​ i = ​0​; i < ​3​; i++) {
arr.push(​function​() {
​console​.log(i)
})
}
​return​ arr;
}

var​ func = myFunctions();


func[​0​](); ​//3
func[​1​](); ​//3
func[​2​](); ​//3

We now have an array, and every item has a function. However, the
function hasn’t been invoked yet. If you log this, you get ​[f, f, f]​ or 3
functions. When we then call each function by ​func[0]()​, 3 gets returned.

During the ​for​ loop, we push a function to the array that logs ​i​, but we
don’t invoke it yet. During the for loop, we increment​ ​i​ until​ ​i​ is equal to
3​. Then when we actually invoke the functions, but we invoke it when ​i​ is
already 3, so they all log 3 as they log ​i​. They can’t find a variable named
i​ in their function, so they go down the scope.

56
2.9 Closures and callbacks

function​ ​sayHiLater​() {
​var​ greeting = ​"Hi"​;
setTimeout(() => {
​console​.log(greeting);
}, ​3000​);
}

sayHiLater();

This is also an example of a closure. ​setTimeout​ takes a function object as


its parameter, which is a first class function in JavaScript. By the time the
function in ​setTimeout​ is invoked, ​sayHiLater​ already stopped running,
but it has to find the variable greeting. It goes up the scope chain and has
a closure for that variable, it knows the memory space.

2.10 bind(), call(), and apply()

.call()
let​ obj = { number: ​10 ​};
let​ addToThis = function(a, b, c) {
​return​ ​this​.number + a + b + c;
}
// functionName.call(object, functionArguments)
console.​log(​addToThis.call(obj, ​1​,​ 2​,​ 3​)); ​// 16

Our ​addToThis​ function returns ​this.number + a​. However, the function


itself doesn’t have a ​this.number​. Therefore, we have to use the ​call
method. The first argument has to be the object! The ​this​ keyword now
refers to ​obj​. What happens if we use an arrow function instead:

let​ obj = { number: ​10 ​};


let​ addToThis = (a, b, c) => {
​return​ ​this​.number + a + b + c;
}
console.​log(​addToThis.call(obj, ​1​,​ 2​,​ 3​)); ​// NaN

57
.apply()
The ​apply​ method is very similar to the call method.

let​ obj = { number: ​10 ​};


let​ addToThis = function(a) {
return this​.number + a;
}

let ​array = [​1​, ​2​, ​3​];


console.​log(addToThis.apply(obj,​ ​array​)); ​// 16

The only difference between ​call​ and ​apply​, is that you can pass the
arguments in an array, which you can’t do with the ​call​ method.

.bind()
The ​this​ keyword doesn’t always refer to the object you expect it to refer
to.

let​ person = {
data: [
{ firstName: ​"Lydia"​ },
];

clickHandler() {
​console​.log(​this​.data[​0​].firstName)
}
}

$(​"button"​).click(person.clickHandler);
// Error (this = button)
$(​"button"​).click(person.clickHandler.bind(person));
// Lydia (this = person object)

When we called the ​clickHandler​ without ​bind​, it threw an error. There is


no ​this​ on the button element. However, after binding, it knew that we
meant the person object, where ​this.data​ is valid.

58
2.11 Functional programming
Because we have first class function in JavaScript, we can implement
functional programming, or in other words: we can think of code in terms
of functions.

2.11.1 Higher-order functions


Higher-order functions are functions that take functions as their
argument.

let​ arr1 = [​1​, ​2​, ​3​];


let​ arr2 = [];
for​ (​let​ i = ​0​; i < arr1.length; i++) {
arr2.push(arr[i] * ​2​)
}
console​.log(arr2); ​// [2, 4, 6]

Luckily, in ES6, one of the great higher-order functions we can use


instead, is called ​map​.

let​ arr1 = [​1​, ​2​, ​3​];


let​ arr2 = arr1.map(x => x * 2​ ​);
console​.log(arr2); ​// [2, 4, 6]

Instead of having to write an entire for loop every time we want to create
another array that returns an array with the multiplied values of arr1, we
use the higher-order function map. Map basically includes that logic
already, so we don’t have to write it! This is just one of the many
examples of a higher-order function. The most common ones in ES6 are
map​, ​filter​ and ​reduce​.

let​ a = arr1.map(x => x * ​3​);


let​ b = arr1.filter(x => x > ​1​);
let​ c = arr1.reduce((cur, acc) => cur + acc);
console​.log(a); ​// [3, 6, 9]
console​.log(b); ​// [2, 3]
console​.log(c); ​// 6

Filter​ and ​reduce​ are explained in ​Common Methods​.

59
2.12 Objects

Almost everything in JavaScript is an object, such as arrays and functions.


An object is a collection of name/value pairs, which values can be
anything, meaning that it can be either a ​primitive type​ or ​another
object​. Objects have ​properties​ and ​methods​ (functions that sit on an
object) and are sitting in the memory with references to the spots where
these properties/methods “live”. You have access to those properties and
methods in memory.

2.12.1 Computed member access operator


The brackets are actually called computed member access operators.
They are used to refer to members of objects.

person[​"firstname"​] = ​"Lydia"

The object will now get a reference to the address location in memory.
The operator takes the object and the property, and looks for it on the
object.

2.13 JSON and Object Literals

JSON:​ JavaScript Object Notation. The most famous format to send data
used to be XML. However, just to send data, you had to send a lot of
unnecessary characters. Luckily, we don’t have to do that anymore with
JSON.

{
"firstname": ​"Lydia"​,
"lastname": ​"Hallie"​,
}

It looks like an object literal, but there are differences. When we receive a
JSON file from our API, we first ​parse​ the data into a variable. We can
then access the data by using the same computed member access
operators as we use for objects, either the dot notation or bracket
notation.
60
The biggest differences between valid JSON and object notation, is that
the keys need to be wrapped in ​double quotes​, an ​array​ is also valid
JSON, and it can ​only contain properties​, no methods! You often
receive a JSON file as a string from a web server. In order to get data out
of it, you use the ​JSON.parse​ method, which converts the text into a
normal object. Before you send data back to the web server, you have to
convert it back into a string by using ​JSON.stringify.

2.14 Functions are objects

Function:​ a special type of


object that resides in
memory​.

The code you write yourself


isn’t the actual function. The
function is an ​object with
other properties,​ and the
code is just one of the
properties. This property is
invocable.
function​ ​bark​() {
​console​.log(​"Woof!"​);
}

bark.animal = ​"dog"​;

This is possible in JavaScript, because functions are objects!

2.15 Function statement vs. function expression

Expression​: a unit of code that results in a value.

Function statement Function expression


function​ ​bark​() { let​ sayWoof = ​function​() {
​console​.log(​"Woof!"​); ​console​.log(​"Woof!"​);
} }

61
The function statement doesn’t result in a value. However, it does get
hoisted​ during the creation phase of the execution context, so it’s
available to you in memory. For the function expression, you’re giving the
variable ​sayWoof​ the value of the function object. The function itself
doesn’t need to have a name, but you can assign it to a variable. The
function is invocable by typing ​sayWoof()​. It is an expression, because
invoking the variable ​results in a value​, which is the function object.

Because it’s assigned to a ​variable​, you cannot invoke the function


object of sayWoof before that variable has been defined. When you try to
run it, you will see ​undefined is not a function ​as the variable ​sayWoof
got hoisted, received the default value of undefined as it hasn’t been
defined yet (but it has been declared).

2.16 By value vs. by reference

All ​primitive types​ interact​ by value.

let​ a = ​4​;
let​ b;

b = a;
​ ​;
a = 2

First, we declare two variables a and b. Then, we set b equal to a, which


is 4 at that point. Later, we give a the value of 2. At this point, b is still 4!
This happens because b has its own space in memory!

All​ objects​ interact ​by reference ​when setting them equal to each other
or passing them to a function.

var​ c = { greeting: ​"Hey!"​ };


var​ d;

d = c;

62
c.greeting = ​"Hello"​;
console​.log(d.greeting); ​// "Hello"

Variable ​c​ holds a reference to an object. Later, we assign ​d​ with the
same reference that ​c​ has to the object. When you change one of them,
you change all of them.

2.17 The keyword ​arguments​ and the spread


operator
When the execution context is created, the​ arguments ​ keyword is set up.
This keyword contains a list of the values of all the parameters that you
pass to a function. This keyword is array-like, meaning that it looks and
acts like an array but it’s not an array, as it doesn’t have all the features.
You can’t use this with arrow functions.

function​ ​showNumbers​(x, y, x) {
​console​.log(​arguments​);
} ​// [1, 2, 3]

showNumbers(​1​, ​2​, ​3​);

The spread operator allows you to pass a random amount of arguments.

function​ ​doSomething​(x, y, z, ...others) {


​console​.log(...others)
} ​// 3 4 2

doSomething(​1​, ​2​, ​3​, ​3​, ​4​, ​2​);

2.18 Inheritance
Inheritance: ​one object gets access to the property and methods of
another object.
Classical inheritance is, compared to prototypal inheritance, a lot of code
to write. You can end up with huge collections, whereas using prototypal
inheritance is very simple and flexible.

63
2.18.1 Understanding the prototype
We have an object in memory with a property. You can access it with the
dot notation or bracket notation. The JavaScript engine adds hidden
properties and methods to things we don’t interact with directly.

All objects, including functions, have a prototype property. ​The


prototype is a reference to another object. ​The prototype is another
object standing on its own.

If we want to access ​obj.prop2​, it first looks on the object. It doesn’t find


it, so then it goes down the​ prototype chain​, and finds it on the
prototype. So, even though ​prop2​ isn’t on your object, it can still access
it. The JavaScript engine does the work for you to go down the prototype
chain, so you don’t have to type ​obj.proto.proto​ etc. If you have another
object, it points to the same prototype. It returns the exact same, as it
has the same spot in memory​.

let​ person = {
firstName: ​'Lydia '​,
lastName: ​'Hallie'​,
getFullName() {
​return​ `${​this​.firstName} ${​this​.lastName}`
}
}

64
let​ otherPerson = {
firstName: ​'John'​,
lastName: ​'Doe'​,
}

With proto, ​this​ refers to the object you’re currently calling it from!

2.19 Primitive or object

Every value is either a primitive or an object. All objects are have


prototypes, except the ​base object​.

var​ a = {};
var​ b = () => { };
var​ c = [];

In your console, when you type a.__proto__ (accessible in Chrome), you


get an empty object. This is the​ base object​ and has access to some
methods and properties, such as ​.toString​. This is the reason why you
can use built-in JavaScript methods! All of such methods are available on
the prototype. Although JavaScript can’t find it directly on your object, it
goes down the prototype chain and finds it there, and makes it accessible
for you. The prototype of variable ​b​ has different properties and methods,
as it’s a function, same for variable ​c​. The prototype of the prototype is
the base object!

65
2.20 Function constructors and the keyword ​new

function​ ​Person ​(firstName, lastName) {


​this​.firstName = firstName,
​this​.lastName = lastName,
}

var​ lydia = ​new​ Person(​"Lydia"​, ​"Hallie"​);

How do you construct a constructor object, set methods, properties and


the prototype? The ​new​ keyword is actually an operator. When you say
new​, immediately a new object is created, as if you created it by using an
object literal. And then, it invokes the function. The execution context
creates a variable called ​this​. When you use the keyword ​new​, it depends
what the ​this​ keyword refers to. When using ​new​, it refers to the new
empty object in memory. (Important, if you forget ​new​, ​this​ refers to the
global object) You’re now adding the ​firstName​ and ​lastName​ property to
that empty object, as these two properties are on the ​Person​ constructor.
The person function is called the function constructor: it lets you construct
objects and is invoked with the keyword ​new.​ If you don’t return anything
from the function constructor, it will set its properties and methods. The
object create by a constructor is called an ​instance​ of that constructor,
and the creation of that instance is called ​instantiation​.

function​ ​Car​(){
​this​.make = ​"Toyota"​;
}

let​ newCar = ​new​ Car();


console​.log(newCar.make); ​//logs Toyota
console.log(newCar ​instanceof​ Car); ​// true
function​ ​Car2​(){
​this​.make = ​"Toyota"​;
​return​ {make: ​"Subaru"​};
} ​// You return, so it sets it to Subaru instead of Toyota

The ​instanceof​ ​operator c​hecks the current object inherits from the
class’s prototype. ​newCar​ is an instance of ​Car​, so it returns ​true​.

66
2.21 Prototype

Every function has a prototype, but only when a function is a ​constructor


it’s actually used. The prototype of the function is not the function’s
prototype: it’s the prototype of every object that’s being created if you’re
using it as a constructor.

Person.prototype

When you call the ​new ​keyword, it sets the prototype to the function’s
prototype that we call.

function​ ​Person​(firstName, lastName) {


​this​.firstName = firstName;
​this​.lastName = lastName;
}
let​ lydia = ​new​ Person(​"Lydia"​, ​"Hallie"​);
Person.prototype.getFullName = () => ​this​.firstName + ​this​.lastName
lydia.getFullName() ​// This now works!

You can add features to all objects at once​, using the prototype
property of the function constructor. It’s very important to remember that
you can’t add properties to the constructor like you can with objects.

Person.language = ​'English'
console​.log(lydia.language) ​// undefined

Person.prototype.language = '​ English'


console​.log(lydia.language) /​ / 'English'

Functions are objects, meaning that they take up memory space. You
could have added the ​getFullName​ function just to the function
constructor, but that would cause a lot of repetition, which would take up
more memory space. But if you add it to the prototype, you have it just
once, which takes up almost no memory space.

67
2.22 Built-in function constructors
There are famous built-in constructors, such as ​new Array()​, ​new String()
or ​new Number()​. The build in function constructor looks like you’re
creating primitives, but you’ve actually creating objects that ​contain
primitives.

String​.prototype.checkLength = ​function​(limit) {
​return​ ​this​.length > limit
}

console​.log(​"John"​.checkLength(​3​)) ​// true

The primitive string was automatically converted into a​ string object​,


generated by the string prototype function. Then, we added a method to
the prototype, so all strings (string objects) suddenly have access to that
method! However, you can’t do this with numbers. JavaScript doesn’t
convert numbers to an object automatically. It is possible though when
we do this:
let​ a = ​new​ ​Number​(​4​);
new Number​ looks like a number, but it’s not. It’s an object that wraps a
number and adds a bunch of features.

let​ a = ​3​;
let​ b = ​new​ ​Number​(​3​);
a == b ​// true
a === b ​// false. A is a primitive, b is an object constructor.

var​ person = {
firstName: ​'default'​,
greet() {
​return​ ​`Hi ${​this​.firstName}`
}
}

var​ john = ​Object​.create(person)

With ​Object.create​, you create an empty object but with the prototype of
the object passed as the argument. You now get all the properties and
68
methods in the prototype, and can overwrite values by writing, for
example:

john.firstName = ​"John"

With p
​ ure prototypal inheritance​, you build an object that becomes the
base of all others.

2.23 Classes
In ES6, it’s possible to use classes instead of function constructors.

class​ ​Person​ {
​constructor​(firstName, lastName) {
​this​.firstName = firstName;
​this​.lastName = lastName;
}

greet() {
​return​ ​"Hi"
}
}

A class defines an object. We have a constructor that acts like the


function constructor. The whole class is an object, and then you’re
creating new objects from that object. The big difference between a class
declaration and a function declaration, is that a class declaration ​is not
hoisted​! You need to create the class before using the​ new​ keyword.
You can create a​ sub-class ​by extending the class.

class​ ​OtherPerson​ ​extends​ ​Person​ {


​constructor​(firstName) {
​super​(firstName)
}

greet() {
​console​.log(​`First name: ​$​{​firstName​}`​)
}
}

69
Super​: calls the parent’s constructor, so the constructor of ​Person​ in our
case. You always have to use ​super​ before using the ​this​ keyword! It
avoids duplicating the constructor parts that are common between the
OtherPerson​ class and the ​Person​ class, so we wouldn’t have to type
this.firstName = firstName​ again. We simply type ​super(firstName)​.

Note that you can’t extend regular objects. If you want to do that, you
have to use ​Object.setPrototypeOf()​.

var​ Animal = {
speak() {
​console​.log(​this​.name + ​' says woof.'​);
}
};

class​ ​Dog​ {
​constructor​(name) {
​this​.name = name;
}
}

Object​.setPrototypeOf(Dog.prototype, Animal);

var​ d = ​new​ Dog(​'Mara'​);


d.speak(); ​// Mara says woof.

2.24 Static methods


Static methods are designed to live only on the constructor in which they
are created, and ​cannot be passed down to any children​.

class​ ​Chameleon​ {
​static​ colorChange(newColor) {
​this​.newColor = newColor;
}

​constructor​({ newColor = ​'green'​} = {}) {


​this​.newColor = newColor;
}
}

70
let​ pantherChameleon = ​new​ Chameleon({newColor: ​"purple"​});
pantherChameleon.colorChange(​"orange"​);
console​.log(pantherChameleon.newColor);

You will see that the ​newColor​ of the ​pantherChameleon​ is still ​purple​, and
that ​pantherChameleon.colorChange​ isn’t a function. That’s because the
function isn’t passed down to the ​pantherChameleon​ instance! You can get
around this by creating two arguments. Classes provide an easy method
to use prototypal inheritance and create constructors. They’re not hoisted,
and will throw an error if an instance is declared before the class. A
constructor function determines what code will be executed when creating
a new instance of the constructor.

2.25 Polyfill
Methods such as ​Object.create​ aren’t always supported by older
browsers. To handle this, you can use a ​polyfill​. A polyfill is code that
adds a feature that the engine may lack.

if​ (!​Object​.create) {
​Object​.create = ​function​(obj) {
​function​ ​NewFunction​() { }
NewFunction.prototype = obj;
​return​ ​new​ NewFunction();
}
}

2.26 Strict mode


It is easy to make typos in your code, without JavaScript throwing an
error.

let​ greeting;
greetign = {};
console​.log(greetign) ​//Object

It logs an object, because we just created an empty object on the global


object! We accidentally mistyped the greeting variable, yet we didn’t get
an actual error. To avoid this, you can use ​use strict​, which makes sure
71
that you have declared a variable before setting it equal to anything.

function​ ​sayHi​() {
​"use strict";
​let​ greeting;
greetign = {};
​console​.log(greetign) ​// Error: greetign is not defined
}

72
FREQUENTLY USED RESOURCES

A very big thanks to all the authors of some of the great resources I’ve
used!

Websites and books


MDN Web Docs
Eloquent JavaScript​ - Marijn Haverbeke

YouTube Channels
Fun Fun Function
JSConf
techsith

Courses on Udemy.com
JavaScript: Understanding the weird parts ​- Anthony Alicea
The Complete JavaScript Course - ​Rob Percival
Advanced JavaScript ​- Asim Hussain

73

You might also like