_iampava
{ about me }
{ about you }
✅ know most/all information from the TW labs
✅ to be resourceful in find solutions on your own
✅ know when to seek help and don't be afraid to do so
✅ help you outside laboratory hours
✅ treat you fair & square
🔥 will have the skills to build not trivial FE projects with a strong focus on Vanilla JavaScript
🤘 will have worked on a personal project which showcases your skills
👨🏭 will be ready to venture into the real world and get into a summer job/internship*
🤝 will have worked with multiple colleagues and thus grow your team-work skills
❌ JS frameworks
❌ CSS pre-processors
❌ accesibility
❌ build tools, deployments etc.
OR
✅ tests during the course
✅ exercises during labs
... each graded with max 2.5 points
🔑 Get at least 5 for all project components and 5 for the course as well as the labs exercises to pass!
Student presentations
VS Code
Git
DevDrive
OK, let's do this! 🔥
<img src="logo.png" alt="logo image">
<h1 data-from="wikipedia">JavaScript rocks</h1>
tag
attribute
custom attribute
<!DOCTYPE html>
<html>
<head>
<!-- -->
</head>
<body>
<!-- -->
</body>
</html>
a {
border-bottom: 2px solid blue;
}
selector
property
value
<p style="font-weight: bold">
A simple styled paragraph...
</p>
<style>
h1 {
text-align: center;
}
</style>
<!-- index.html -->
<link rel="stylesheet" href="style.css" />
<!-- style.css -->
footer {
color: #000;
background-color: #fff;
}
<img class="image round-image" id="profile"
src="user.jpg" />
<style>
img {
border: 1px solid black;
}
.round-image {
border: 5px dotted yellow;
}
.image {
border: 10px dotted red;
}
#profile {
border: 2px solid blue;
}
</style>
inline
#id
class
Tag
💥 !important
.valentines.in-love {
// both "valentines" & "in-love"
// classes
text-decoration: make-up;
}
.raining .human {
/* "human" class elements inside a
"raining"-class element
*/
display: hidden;
position: under-blanket;
}
.raining.valentines .in-love {
color: red;
}
faculty.in-iasi.state-owned .b4 #gicu {
display: none;
}
<style>
.red {
color: red;
}
.blue {
color: blue;
}
</style>
<p class="red blue"> Bob </p>
<p class="blue red"> Alice </p>
✅ finish styling "Simon Says"
✅ deploy it to GitHub pages
✅ make a Twitter account & follow these awesome devs
📅 FII IT'ist | 13 Oct
9 Oct @TheGrape
Text
Week #2
❌ DOM transaction are expensive!
function colorPattern(values) {
for (let i=0; i < values.length; i++) {
document
.getElementById(`button-${values[i]}`)
.style.backgroundColor = "red";
}
}
<button id="b1"> 1 </button>
<button id="b2"> 2 </button>
<!-- ... -->
<script>
function onClick(e) {
let value = e.target.substrig(1);
console.log(`Clicked the ${value } button`);
}
</script>
❌ Don't use ID's or classes for storing info
<div>
<button id="b1"
onclick="click()"> 1 </button>
<button id="b2"
onclick="click()"> 2 </button>
</div>
❌ Don't use memory with tons of event listeners!
Any about Projects?
Bonus
Bonus
✔ Play/Pause
✔ Track for changing position
✔ Volume & Play speed
✔ Custom styles
🆕🆕 Grid
🆕 Flexbox
🧓 Position
STATIC
RELATIVE
ABSOLUTE
FIXED
Sticky
🧓 Position
BLOCK
INLINE-BLOCK
INLINE
🧓 TABLE
🆕 FLEXBOX
🆕 GRID
🈹 Display 🈹
<body>
<section class="question">
<p class="question__body">
Do you even bike?
</p>
<p class="question__answer">
No
</p>
<p class="question__answer
question__answer--selected">
Yes
</p>
</section>
</body>
#logo {
tranform: scale(1.1) rotate(35deg);
}
#logo {
transform: scale(1.1) rotate(30deg);
transform-origin: 0 0;
}
/* transform-origin: center | top left | top right | ... */
.5 sec
#logo {
transition: transform .5s ease-in;
}
#logo:hover {
transform: scale(1.1);
}
property
timing function
duration
A
A
A
A
#logo {
animation: rotate 1s linear infinite;
}
@keyframes rotate {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(180deg);
}
100% {
transform: rotate(360deg)
}
}
duration
name
timing function
iteration count
✅ cusom style a <video> element
Week #3
@media screen and (max-width: 450px) {
/* ... */
}
@media screen and (orientation: portrait) {
/* ... */
}
@media (prefers-color-scheme: dark) {
/** ... */
}
1 - Server-side solution
give me `cover.jpg`
seems like you're on mobile
sending `cover_small.jpg`
<picture>
<source
srcset="image_high.jpg"
media="(min-width: 800px)">
<source
srcset="image_low.jpg"
media="(min-width: 450px) and (max-width: 800px)">
<img src="image_very_low.jpg" alt="image">
</picture>
2 - Client side solution
@media screen and (min-width: 800px) {
.cover {
background: url('cover_high.jpg');
}
}
@media screen and (max-width: 800px) {
.cover {
background: url('cover_low.jpg');
}
}
Bonus
one dimension
..or..
row
column
Flex Container
flex
items
ul {
display: flex;
}
ul {
flex-direction: row;
}
ul {
flex-wrap: wrap;
}
ul {
flex-flow: column wrap-reverse;
}
ul {
justify-content: center;
}
ul {
justify-content: space-between;
}
ul {
justify-content: space-around;
}
Align along the main-axis!
ul {
justify-content: space-evenly;
}
ul {
align-items: center;
}
Align along the cross-axis!
li {
order: 5;
}
Re'order items!
li {
flex-grow: 0;
flex-shrink: 1;
flex-basis: 25%;
}
Grow, shrink, basis
li {
flex: 0 1 25%;
}
flex items
li {
order: 5;
flex: 0 1 25%;
}
flex container
ul {
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: flex-start;
}
making a GRID system using Flexbox
two dimensions
row
column
CSS Grid Layout is the most powerful layout system available in CSS.
No more 'row' syntax!
Grid Container
grid
items
ul {
display: grid;
grid-gap: 1em;
}
Let's align them in a row!
.box-2
.box-3
.box-4
.box-1
.box-1 {
grid-column: 1/2;
}
.box-2 {
grid-column: 2/3;
}
.box-3{
grid-column: 3/4;
}
.box-4{
grid-column: 4/5;
}
Let's align them in 2 rows!
.box-2
.box-3
.box-1
.box-4
.box-1 {
grid-column: 1/2;
grid-row: 1/2;
}
.box-2 {
grid-column: 2/3;
grid-row: 1/2;
}
.box-3{
grid-column: 1/2;
grid-row: 2/3;
}
.box-4{
grid-column: 2/3;
grid-row: 2/3;
}
Let's give them sizes!
ul {
grid-template-columns: 10px 50px;
grid-template-rows: repeat(2, 50px);
}
Another size unit!
ul {
grid-template-columns: .5fr 3fr;
grid-template-rows: repeat(6, 1fr);
}
grid items
li {
grid-column: 3/4;
grid-row: 1/2;
}
grid container
ul {
display: grid;
grid-gap: 1em;
grid-tempalte-columns: repeat(4, 100px);
grid-template-rows: 50px 50px;
}
Let's give them names! 🔥
ul {
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(4, 1fr);
grid-template-areas:
"header header header header"
"aside aside main main"
"aside aside main main"
"footer footer footer footer";
}
.header {
grid-area: header;
}
.aside{
grid-area: aside;
}
.main {
grid-area: main;
}
.footer {
grid-area: footer;
}
footer
aside
main
header
Ready? Set! GO!
Explicit vs implicit grid!
ul {
grid-template-columns: repeat(3, 20px);
grid-template-rows: 10px 50px;
}
?
Let's make it responsive!
ul {
grid-template-columns:
repeat(auto-fill, minmax(350px, 1fr));
}
✅ start working on the PROJECT!
Week #4
❓ decide on 5 HTML and/or CSS questions which you will ask the other team in phase #2
📄 exchange questions with the other team
🤔 discuss for 5 minutes the answers
🔁 in turns, a different team member from each team answers a question. 1 point if it's correct, 0 points otherwise
❗ a member may chose to revert the question by appointing someone from the other team to answer. If they don't know, they lose 1 point. This can be done a max of 2 times per team
Schema.org is a collaborative, community activity with a mission to create, maintain, and promote schemas for structured data on the Internet [...]
🔨 A practical usecase
Google Search works hard to understand the
content of a page.
You can help us by providing explicit clues about the meaning of a page to Google by including structured data on the page.
Microdata
JSON+LD
Microdata
An open-community HTML specification used to nest structured data within HTML content.
<div itemscope itemtype="http://schema.org/Product">
<span itemprop="brand">ACME</span>
<span itemprop="name">Executive Anvil</span>
<img itemprop="image" src="anvil_executive.jpg" alt="Executive Anvil logo" />
<span itemprop="description">Sleeker than ACME's Classic Anvil, the
Executive Anvil is perfect for the business traveler
looking for something to drop from a height.
</span>
Product #: <span itemprop="mpn">925872</span>
<span itemprop="aggregateRating" itemscope itemtype="http://schema.org/AggregateRating">
<span itemprop="ratingValue">4.4</span> stars, based on <span itemprop="reviewCount">89
</span> reviews
</span>
<span itemprop="offers" itemscope itemtype="http://schema.org/Offer">
Regular price: $179.99
<meta itemprop="priceCurrency" content="USD" />
$<span itemprop="price">119.99</span>
(Sale ends <time itemprop="priceValidUntil" datetime="2020-11-05">
5 November!</time>)
Available from: <span itemprop="seller" itemscope itemtype="http://schema.org/Organization">
<span itemprop="name">Executive Objects</span>
</span>
Condition:
<link itemprop="itemCondition" href="http://schema.org/UsedCondition" />Previously owned,
in excellent condition
<link itemprop="availability" href="http://schema.org/InStock" />In stock! Order now!
</span>
</div>
<div itemscope></div>
<div
itemscope
itemtype="https://schema.org/Person">
</div>
<div
itemscope
itemtype="https://schema.org/Person">
<span itemprop="name"> John Doe </span>
</div>
🔗 The itemtype attribute [...] value is an unordered set of unique [...] valid absolute URLs, all of which are in the same vocabulary.
JSON+LD
<script type="application/ld+json">
{
"@context": "http://schema.org/",
"@type": "Product",
"name": "Executive Anvil",
"image": [
"https://example.com/photos/1x1/photo.jpg",
"https://example.com/photos/4x3/photo.jpg",
"https://example.com/photos/16x9/photo.jpg"
],
"description": "Sleeker than ACME's Classic Anvil, the Executive Anvil is perfect for the business traveler looking for something to drop from a height.",
"mpn": "925872",
"brand": {
"@type": "Thing",
"name": "ACME"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.4",
"reviewCount": "89"
},
"offers": {
"@type": "Offer",
"priceCurrency": "USD",
"price": "119.99",
"priceValidUntil": "2020-11-05",
"itemCondition": "http://schema.org/UsedCondition",
"availability": "http://schema.org/InStock",
"seller": {
"@type": "Organization",
"name": "Executive Objects"
}
}
}
</script>
Organization
Recipe
✔ important ideas/concepts regarding overall design
✔ user interaction methods
✔ ways of using the management system
🔗 In depth
Week #6
✅ it's single threaded
✅ it's a dynamic language
✅ it's an open language, actively developed by TC39
✅ everything in the same global scope
✅ naming convention is usually camelCase
✅ officially called EcmaScript, that's why version are called ES5, ES6, etc...
// Object creation
let myBake = {
mark: "unknown",
year: 2015,
boughtFrom: {
name: "Decathlon",
address: "Era Shopping Park"
}
}
// Get properties
console.log(myBike.boughtAt.name);
console.log(myBike["boughtAt"]["name"]);
// Add properties
myBike.suspension = "full";
// Object creation
let veryRandomList = [
2, null, undefined, "bob",
[1, 2, 3]
];
console.log(veryRandomList[3]);
// Arrays are Objects too
veryRandomList.name = "My List";
console.log(veryRandomList);
function study(subject, until = "20:00") {
console.log(`Studying ${subject} until ${until}`;
}
// I prefer to put running code first...
button.addEventListener("click", study);
// and functions last.
✔ can be named or anonymous
✔ doesn't brake if missing params. It's a dynamic lang 😅
✔ if no explicit return, it implicitly returns undefined
✔ are first class citizens - whatever you can do with the other variables you can do with functions
returned from functions
passed to functions as arguments
stored in variables
❗ Where can we access the declared variables?
Function scope
⭐ access inside same-scope
⭐ access from inner scope to outer scope
block scope vs function scope
function goOut() {
if (weather === "sunny") {
let outfit = "light & casual";
} else {
let outfit = "light & casual + umbrella";
}
console.log(outfit);
}
Block scope
function goOut() {
const outfit;
if (weather === "sunny") {
outfit = "light & casual";
} else {
outfit = "light & casual + umbrella";
}
console.log(outfit);
}
Error
Error
const cannot be reassigned
const person = {
name: 'Bob',
occupation: 'JavaScriptER',
umbrella: true
};
if (weather === 'sunny') {
person.umbrella = false;
}
✔
Let's put it all together...
function startGame() {
const name = "Game";
function baz() {
var x = 2;
if(x ===2) {
let x = 3;
console.log(x);
}
{
// creating a block
const x = 33;
}
}
}
startGame();
function startGame() {
let players = [{
name: "Alice",
gold: 120,
life: .75
}, {
name: "Bob"
life: 1
}];
for(let i = 0; i< players.length; i++) {
console.log(getChangeToWin(players[i]));
}
}
function getChangeToWin(player) {
return player.gold ** 2 * player.life;
}
⭐ The ability of a function to access lexical scope variables even when it is executed in a different context.
function simpleF(x) {
return function() {
return x;
}
}
let get11 = simpleF(11);
console.log(get11);
The prototype represents the collection of properties and methods that all instances of a certain type/class inherit.
All Array's have a sort function already defined by the language. We say that the sort function is on the Array prototype.
⭐ We can add properties/methods to the prototype... ⭐ And even delete them...
{
}
let myBike = new Bike("Buburuza");
myBike.ride();
function Bike() {
this.name = name;
}
Bike.prototype.ride = function() {
console.log(`I'm riding ${this.name} bike`);
}
ES5
let myBike = new Bike("Buburuza");
myBike.ride();
class Bike {
constructor(name) {
this.name = name;
}
ride() {
console.log(`I'm riding ${this.name} bike`);
}
}
ES5
class SuperBike extends Bike{
constructor(name, power) {
super(name);
this.power = power;
}
getPower() {
console.log(`My power is ${this.power}`);
}
}
ES5
Problem...?
That's right, private is messy... Here's how we create private methods and make sure name is not changable.
class Bike {
constructor(name) {
this.getName = () => name;
function privateF() {
// ...
}
}
ride() {
console.log(`I'm riding ${this.getName()} bike`);
}
}
✅ finish the Practice-OOP exercise & send it to me for feedback & bonus points
Week #7
❗ The only way to achieve public and private methods in JS
🎉 by using CLOSURES, of course!
function MathModule() {
}
(function MathModuleIIFE() {
}());
window.PI = (function MathModuleIIFE() {
return 3.14;
}());
console.log(PI);
window.MathM = (function MathModuleIIFE() {
const PI = 3.141231231231;
return {
powPI: function powPI(x) {
return x ** PI;
},
getPI: function getPI() {
return PI;
}
}
}());
MathM.powPI(2); // ...
This is what many libraries out there are doing...
❗ But, how do I access the public API from my module?
😎 revealing module pattern to the rescue!
window.MathM = (function MathModuleIIFE() {
const PI = 3.141231231231;
return {
powPI,
getPI
}
function powPI(x) {
return x ** PI;
}
function getPI() {
return PI;
}
}());
MathM.powPI(2); // ...
now we can access the public methods from inside the Pet
Using the module pattern is generally not recommended for class/instance usecases.
For those use the contructor/class pattern!
for (let i = 0; i < 10; i++ ) {
console.log(`Iteration number ${i}`);
}
console.log('Chuck Norris is a badass');
console.log('Wait, what?');
setTimeout(function textBob() {
console.log('On my way!');
}, 2000);
document
.getElementById('logo')
.addEventListener('click', textBob);
function textBob() {
console.log("On my way!");
}
A callback is a function invoked from another function which received it as a parameter.
setTimeout(textBob, 500);
document
.getElementById("logo")
.addEventEventListener("click", textBob);
callback
callback
Callbacks enable decoupling
Game engine
Hero Class
life decreases every second
interested
class Hero(name, onUpdate) {
constructor() {
setInterval(() => {
// do stuff
onUpdate(data);
}
}
}
let GameEngine = (function (){
let newHero = new Hero(
"Bob",
onHeroUpdate
);
function onHeroUpdate(data) {
// do stuff
}
}());
But can lead to callback hell 👿
fs.readdir(source, function (err, files) {
if (err) {
console.log('Error finding files: ' + err)
} else {
files.forEach(function (filename, fileIndex) {
console.log(filename)
gm(source + filename).size(function (err, values) {
if (err) {
console.log('Error identifying file size: ' + err)
} else {
console.log(filename + ' : ' + values)
aspect = (values.width / values.height)
widths.forEach(function (width, widthIndex) {
height = Math.round(width / aspect)
console.log('resizing ' + filename + 'to ' + height + 'x' + height)
this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
if (err) console.log('Error writing file: ' + err)
})
}.bind(this))
}
})
})
}
})
We're usually using callbacks with DOM events so... regarding that
food example
let goodPromise = Promise.resolve("hello");
goodPromise.then(
(resp) => console.log(resp)
);
let badPromise = Promise.reject("nay");
badPromise.then(
(resp) => {},
(err) => console.error(err)
);
let after5Seconds= new Promise((resolve, reject) => {
setTimeout(() => {
resolve(Date.now());
}, 5000);
});
after5Seconds.then(
resp => console.log(`The time is ${resp}`),
err => console.error(err)
);
Promise.prototype.then and Promise.prototype.catch return a promise.
Promise.resolve(2)
.then(x => x + 2)
.then(y => y * 2)
.then(z => z * 10)
.then(final => console.log(final));
getUsers()
.then(users => users.filter(/* ... */))
.then(users => users.map(/* ... */));
getUser("bob")
.then(user => getResults(user, "js-test")
.then(results => results.filter(r => r.total > 50))
.then(/* ... */);
action1().then(resp1 => { action2(resp1).then(resp2 => { action3(resp2).then(resp3 => { console.log(resp3); }, err3 => {/* ... */}) }, err2 => {/* ... */} }, err => {/* ... */}
there's gotta be a better way!
action1()
.then(resp1 => action2(resp1))
.then(resp2 => action3(resp2))
.then(resp3 => console.log(resp3))
.catch(err => console.log("Error above"));
action1()
.then(resp1 => action2(resp1))
.then(resp2 => action3(resp2))
.catch(err => {
console.log("Error at 1 or 2");
return fallbackObj;
})
.then(resp3 => console.log(resp3))
.catch(err => console.log("Error at 3"));
the modern way of doing ajax requests ❤
fetch(url, options);
fetch("url")
.then(resp => console.log(resp));
fetch("url")
.then(resp => resp.json())
.then(jsonResp => console.log(jsonResp));
fetch("url")
.then(resp => resp.text())
.then(textResp=> console.log(textResp));
👊 Chuck Norris API 👊
Week #10
+ a little async
When users navigate to a video, you need to:
1) check for permissions
2) get the actual video data
Scalable Vector (math drawn) Graphics!
crisp and responsive on any display!
easy to animate
easy to make accessible
<svg width="200" height="250" version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect x="10" y="10" width="30" height="30" stroke="black" fill="transparent" stroke-width="5"/>
<circle cx="25" cy="75" r="20" stroke="red" fill="transparent" stroke-width="5"/>
<ellipse cx="75" cy="75" rx="20" ry="5" stroke="red" fill="transparent" stroke-width="5"/>
<line x1="10" x2="50" y1="110" y2="150" stroke="orange" stroke-width="5"/>
<polyline points="60 110 65 120 70 115 75 130 80 125 85 140 90 135 95 150 100 145" stroke="orange" fill="transparent" stroke-width="5"/>
<polygon points="50 160 55 180 70 180 60 190 65 205 50 195 35 205 40 190 30 180 45 180"
stroke="green" fill="transparent" stroke-width="5"/>
<path d="M20,230 Q40,205 50,230 T90,230" fill="none" stroke="blue" stroke-width="5"/>
</svg>
M, m | moveTo |
L, l | lineTo |
H, h | horizontal line drawn from current position |
V, v | vertical line drawn from current pos |
Z, z | joins the end of a path |
🎨 Animate the arms of the character!
Imagine a blank Canvas on which you can programmatically paint stuff!
geometrical shapes
images
...or even pixel by pixel
Custom visualizations
Games
... or maybe just Graphics!
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.rect(10, 100, 50, 50);
ctx.fill();
🎨 Draw some mountains, a sky and a sun!
✅ beginPath();
✅ rect();
✅ moveTo(); lineTo();
✅ arc();
✅ fill(); stroke();
Animating stuff is like making movies!
We paint the canvas many many times a second which gives the illusion of movement.
window.requestAnimationFrame(function onFrame() {
/* ... */
});
window.requestAnimationFrame(function onFrame() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.rect(51, 100, 50, 50);
ctx.fill();
});
🎨 Draw and animate some birds flying across the scene!
Week #11
JavaScript code that runs independently (separate thread) from the browser.
perfect for doing intensive work in a non-blocking fashion
let myWorker = new Worker("worker.js");
// Later...
myWorker.postMessage("Here's some data");
// worker.js
self.onmessage = function () {
// ...
}
// OR
self.addEventListener("message", () => {
// ...
});
But wait... There's more!
Still a worker...but shared between windows. Meaning, all of them have the same worker reference
for sharing computations/state among browser windows!
code...
// shared-worker.js
let ports = [];
self.onconnect = function (e) {
var newPort = e.ports[0];
self.ports.push(newPort);
newPort.onmessage = function (e) {
// ...
}
newPort.postMessage(/* ... */);
}
let myWorker = new SharedWorker("shared-worker.js");
What? Another one?
Still a worker...but more special 😎
only one per page with a very special lifecycle
keeps working even after closing the browser
can intercept & respond to requests as if they were actually coming from the server
can intercept push notifications
// service-worker.js
self.addEventListener('fetch', (event) => {
if (
event.request.destination === "image"
||
event.request.url.includes(".jpg")
) {
event.respondWith(
fetch("/chuck-norris.jpg"); // 😜
);
}
});
Small hack: instead of the actual images use Chuck Norris ones!
Faster, both-way communication between client & server.
perfect for real time apps: chats, games, stock prices, etc...
// Create WebSocket connection.
const socket = new WebSocket('url');
socket.addEventListener('open', (event) => {
socket.send('Hello!');
});
socket.addEventListener('message', (event) => {
console.log('Got message!', event.data);
});
Week #12
LESS is MORE!
...
Week #13
obj.sayHello();
let foo = {
name: "Foo",
sayHello: function() {
console.log(`Hello ${this.name}`);
}
}
let bar = {
name: "Bar"
}
bar.sayHello = foo.sayHello;
foo.sayHello(); // ?
bar.sayHello(); // ?
foo.call(newThis, ...) foo.apply(newThis, [...])
let foo = {
name: "Foo",
sayHello: function() {
console.log(`Hello ${this.name}`);
}
}
let bar = { name: "Bar"}
foo.sayHello(); // ?
foo.sayHello.call(bar); // ?
foo.bind(newThis)
let foo = { name: "Foo" }
let bar = { name: "Bar" }
function sayHello() {
console.log(`Hello ${this.name}`);
}
foo.sayHello = sayHello.bind(bar);
foo.sayHello(); // ?
function sayHello() {
console.log(`Hello ${this.name}`};
}
sayHello();
New keyword
Explicit binding
Implicit binding
Default rule
Arrow functions
Do not have their own this! They `borrow` it from the enclosing scope.
Before arrow functions...
class Bike {
constructor() {
this.type = "Mountain bike";
let self = this;
setTimeout(function() {
console.log(self.type);
}, 1000);
}
}
With arrow functions...
class Bike {
constructor() {
this.type = "Mountain bike";
setTimeout(() => {
console.log(this.type);
}, 1000);
}
}
Timeout & Interval
setTimeout and setInterval have their `this` bound to the window.