JavaScript, ES6 - Lecture 1 - CS50's Mobile App Development with React Native 2018
Estimated read time: 1:20
Summary
In the opening lecture of CS50's Mobile App Development with React Native, we dive deep into JavaScript and its modern version, ES6. We begin with a recap on data types, coercion, and objects, then explore complex topics such as prototypal inheritance, scope, and the nuances of ECMAScript versions. The lecture explains the implementation of ECMAScript via JavaScript, touches on syntax use with tools like Babel, and delves into closures and their quirks. Additionally, the session covers synchronous vs asynchronous JavaScript using execution stacks and functions like setTimeout, transitioning into the world of callbacks, Promises, and Async/Await for handling asynchronous operations efficiently. Lastly, the session introduces the 'this' keyword, provides insights into DOM manipulation for web development, and introduces the first coding project on creating a to-do app using these concepts.
Highlights
Exploring JavaScript's ECMAScript roots links the language to a broader family of scripting languages π.
Master closures to unlock powerful JavaScript patterns, retaining function access to external variables π.
Navigate through various JavaScript versions to leverage tools like Babel for backward compatibility π.
Unravel the mystery of 'this' in JavaScript to control object methods and properties more effectively π΅οΈ.
Asynchronous operations, when synchronized efficiently with Promises and Async/Await, streamline complex workflows β±οΈ.
Dive into DOM manipulation to bring interactive and dynamic elements to web applications π§.
Key Takeaways
JavaScript is built on the ECMAScript specification, ensuring a standard framework for the language π.
Understanding closures is key to mastering JavaScript's function scope and memory management π§ .
ECMAScript versions evolve, bringing powerful new features like 'let', 'const', and arrow functions π.
Asynchronous JavaScript can be handled using callbacks, Promises, and the newer Async/Await syntax π’.
The DOM (Document Object Model) tree structure is vital for dynamic web page manipulation π³.
Learn how 'this' can change context based on where a function is called from, crucial for object-oriented programming π―.
Overview
The talk kickstarts by differentiating JavaScript from its specification, ECMAScript, shedding light on the JS landscape. It walks through the differences between ES5, ES6, and beyond, emphasizing tools like Babel that enable modern syntax across various environments. The lecture then delves into closures, illustrating JavaScript's capability to remember its execution context and showcasing practical applications and common pitfalls.
Progressing into asynchronous JavaScript, the session uncovers the intricacies of synchronous vs asynchronous execution using concepts like stack, browser APIs, and the event loop. By demonstrating functions like setTimeout, the session clarifies how JavaScript handles asynchronous tasks even as a single-threaded language. The transition from callbacks to Promises, and finally to Async/Await, highlights the evolution towards more manageable asynchronous code.
Finally, the lecture covers the dynamic keyword 'this,' demonstrating how its context can shift in object methods. The session concludes with an introduction to the DOM, picturing it as a tree that represents the structure of a webpage, and teasing the first coding projectβa to-do app that employs DOM manipulation. This introduction sets a practical stage for applying JavaScript concepts in real-world web development.
Chapters
00:00 - 03:00: Welcome and Introduction to ES6 Chapter 1: Welcome and Introduction to ES6 - The chapter starts with a musical introduction and a welcome message. The speaker begins by introducing the first lecture of the week, which will focus on diving deeper into JavaScript, specifically ES6. The speaker briefly references the previous lecture's topics, reminding the audience about the discussion on different types in JavaScript, and prompts the audience to recall and name some of the types discussed last week.
03:00 - 10:00: JavaScript Types and Coercion The chapter covers JavaScript types and coercion. The key types discussed include strings, numbers, null, undefined, objects, symbols, and booleans. The concept of coercion, which involves converting one type to another, is also addressed, differentiating from objects which are considered non-primitive types.
10:00 - 15:00: Scope and Prototypal Inheritance The chapter titled 'Scope and Prototypal Inheritance' covers the concept of prototypal inheritance, a complex topic previously discussed. It describes prototypal inheritance as a process allowing a complex object to have methods and properties. The chapter also touches on the concept of scope, which determines the lifespan of a variable.
15:00 - 21:00: ECMAScript Versions and Transpilers The chapter begins by discussing the process of how JavaScript is executed, mentioning the global object, and introducing the concept of closures, which will be elaborated later. Before delving into closures, the chapter provides background information on ECMAScript versions such as ES5, ES6, 2016, 2017, and ESNext. It explains that ECMAScript is essentially the specification for JavaScript, detailing the expected behaviors and functionalities of the language.
21:00 - 29:30: Closures in JavaScript JavaScript implementations are based on the ECMAScript specification. New ECMAScript versions are released annually, which presents a challenge for JavaScript developers. They often struggle to anticipate the environments in which their code will execute, leading to uncertainty in feature support. Developers generally rely on conventions to manage compatibility issues.
29:30 - 40:00: Higher-Order Functions The chapter discusses the concept of higher-order functions in programming, particularly in the context of JavaScript. It introduces the importance of transpilers, tools that convert code written in the latest language versions into a form that is backward-compatible with older specifications like ES5. This allows developers to utilize modern features and maintain compatibility across different environments.
40:00 - 57:00: Synchronous and Asynchronous JavaScript The chapter discusses Synchronous and Asynchronous JavaScript with a focus on the use of modern JavaScript syntax defined by ES6, ES2016, and later versions. It explains the process of transpiling, where modern code (ES6 and beyond) is converted into ES5 code for compatibility. Popular transpilers mentioned include Babel, TypeScript, and CoffeeScript. The text suggests using future syntax as either the language and environments will catch up or the code can be transpiled back to ES5.
57:00 - 67:00: Introduction to Callbacks The chapter titled 'Introduction to Callbacks' begins with a mention of the extensive use of ES6 and beyond features in the course. The transcript recalls a previous discussion about closures. It explains that closures allow functions to retain access to variables declared by a parent function, even after the parent function has finished execution and is no longer present. This highlights a fundamental aspect of how closures work in JavaScript, serving as a foundational concept for understanding callbacks in programming.
67:00 - 81:00: Promises as a Solution to Callback Hell The chapter delves into how promises can be used as a solution to 'callback hell' in JavaScript. The discussion includes an explanation of JavaScript scoping and closures with a practical example. An exploration of a potential bug with closures, as introduced in a prior lecture, is also included.
81:00 - 93:00: Async/Await Introduction The chapter introduces the concept of Async/Await in programming. It discusses how these constructs work in JavaScript, particularly in handling asynchronous operations more smoothly and efficiently. The discussion may include how async functions return promises, and how 'await' pauses the execution of an async function until the promise is resolved. The example given involves pushing a series of functions into an array, highlighting how async/await makes handling such tasks straightforward in contrast to traditional methods like callbacks and promises.
93:00 - 112:00: Understanding 'this' in JavaScript This chapter focuses on understanding the 'this' keyword in JavaScript by illustrating a practical example. It starts with creating a new empty array and iterating through numbers 0 through 5, where functions are pushed to the array. Each function logs the number 'i'. These functions are then invoked, demonstrating how 'this' works in different contexts when the functions are executed.
112:00 - 122:00: Document Object Model (DOM) In this chapter, the focus is on understanding why a certain JavaScript code behavior occurs, specifically why it logs a different number than initially expected. The explanation begins with a deeper exploration of closures. Closures are defined as functions that have access to variables within their own scope, the scope of a parent function, and the global scope. A particular code snippet that logs the number 5 instead of 0 is highlighted, setting the stage for a detailed exploration of closures and their impact on such outcomes.
122:00 - 130:00: Conclusion and Project Introduction The chapter begins by acknowledging that certain topics or concepts might have been previously covered and are no longer within the current scope of discussion. Then, the focus shifts to a more practical task of creating a function, suggesting a hands-on approach to solidify understanding towards the end of the course or series. This transition marks a shift from theoretical or broad topics to a more specific and practical application, indicative of a conclusion to previous lessons and an introduction to a project-based or applied learning task.
JavaScript, ES6 - Lecture 1 - CS50's Mobile App Development with React Native 2018 Transcription
00:00 - 00:30 [MUSIC PLAYING] SPEAKER 1: All right. Hello. Welcome back for Lecture One. And this week, we're going to
be diving into more JavaScript and talking about ES6. So previous lecture, we talked about a
few different topics, types being one. Who can name some types that
we talked about last week?
00:30 - 01:00 Anyone? AUDIENCE: String. SPEAKER 1: A string. AUDIENCE: A number. SPEAKER 1: A number. AUDIENCE: Null. SPEAKER 1: Null. AUDIENCE: Undefined. SPEAKER 1: Undefined. AUDIENCE: Object. SPEAKER 1: Object. And--- AUDIENCE: A symbol. SPEAKER 1: A symbol. And-- true or false. A boolean. Yeah. We talked about coercion, which
was the process by which we change one type to other. Objects, of course,
the non primitive type.
01:00 - 01:30 Prototypal inheritance. Who can remember what
prototype inheritance was? This was one of the complex
topics from last week. Yeah. AUDIENCE: [INAUDIBLE] SPEAKER 1; Yeah, exactly. It's the process by which a more complex
object can have methods and properties. We talked about scope which is
basically how long a variable lives.
01:30 - 02:00 How JavaScript gets executed. The global object, and I left you
on a cliffhanger about closures. But before we dive into
closures, I just want to give a little bit of
more background on what these ES5, ES6, 2016, 2017,
ESNext, what are those? So we talked a little bit last
week on what ECMAScript was. ECMAScript is basically
the spec for this language. It defines exactly what
this language should do and how much of these functions behave.
02:00 - 02:30 And JavaScript is actually an
implementation of ECMAScript spec. And so which of these versions
do environments support? Because every year, roughly,
a new version comes out. So this is a little bit
of a tricky question. It's kind of the bane of all
JavaScript programmer's existence. Because we really don't know
exactly what environment our code is going to be run in. And therefore, we don't really
know exactly what is supported. And so, generally, what
we do is the convention
02:30 - 03:00 is to assume that the
environment supports all of ES5. And so what are we supposed to do
about these future language things that we can use? A big thing in JavaScript right
now is what's called a transpiler. A transpiler is basically some code
that goes from newer language features and actually makes it backwards
compatible with the ES5 spec. So, basically, it takes all of your
new language, any functions you
03:00 - 03:30 are using that is defined
by ES6, ES2016 and beyond, and actually turns them into
code that's basically ES5 code. So some of these, the most
popular one is probably Babble. But other ones you may have heard of
are TypeScript, or CopyScript, etc. So which syntax should we use? Generally, what people do is
they use the future syntax because either the language and
the environments will catch up, or we just transpile things back to ES5. Does that makes sense to everybody?
03:30 - 04:00 So in course, we will be using a
lot of ES6 and beyond features. Cool. So going back to last week, we
talked a bit about closures. At least I showed you exactly what
the problem behind closures were. But to explain exactly what they
are it's functions basically have access to variables that are
around when functions are defined. And these functions
actually retain the ability to use variables declared
by a parent function even after that parent function has
returned and possibly disappeared.
04:00 - 04:30 And this is possible because
of JavaScript scoping. And so let's see an example
of how this works in action. So last week I talked about a
possible bug with using closures. And let me just type
that out really quick. So we had a function. And basically what it does
is it creates a new array
04:30 - 05:00 and pushes a bunch of
functions to that array. And so let's do--
05:00 - 05:30 So does everybody following
along what's going on here? So, basically, I'm
creating a new empty array. I'm iterating through the numbers 0
through 5 and pushing on to a function to that array, which
will cancel that log i. And then I'm going ahead and
invoking that and storing the return as function array. And I'm going in and
invoking the first one.
05:30 - 06:00 And as we saw last week, even though
we expected this to console.log0, it actually console logs 5. And so this week, we're
going to go ahead and explain exactly why that happens. So before we do that, let's actually
explore closures a little more deeply. And so what did we say a closure was? A closure is basically a function
that has access to some variables that
06:00 - 06:30 might have already left scope. So, basically, let's create a function--
06:30 - 07:00 OK. So what I just did here
is I wrote a function that declares a variable called message. This message is just set
to the string called hello. And then we create a new function that
console logs a variable called message.
07:00 - 07:30 And then return that function. And so at line 11, we invoke that. And so at line 12, what is
the value of message here? Can anybody tell me? AUDIENCE: [INAUDIBLE] SPEAKER 1: Yeah. it's
going to actually error. Because there's no such
thing called message. Yet so let's just confirm that. We have an error because
message is not defined.
07:30 - 08:00 But now let's comment
the out and run the code. And what we see is that say hello will
actually console.log that message. And so let's dive a little
bit more deeply into this.
08:00 - 08:30 So we see that type of message
at that point is undefined. And if we console.log say
hello is is console logging a variable called message. And when we invoke that it prints hello. And so that there is a closure. Because we can see that the variable
called message when say hello is invoked does not actually exist.
08:30 - 09:00 Yet say hello still has access
to this message up here. Because it was within scope
when that function was created. And so that is what a closure is. Does that make sense to everybody? Yeah. AUDIENCE: [INAUDIBLE] SPEAKER 1: No. So the question was,
would it make a difference if rather than having a const
here we had a var or a let, and, no, it does not.
09:00 - 09:30 Any other questions about
this closure example? No. So and now let's go ahead and
explore exactly why this bug exists. And so here what is the value of i? Can anybody tell me?
09:30 - 10:00 Is it 4? Right here at line 13. Yeah. AUDIENCE: [INAUDIBLE] SPEAKER 1: Yeah, it's going
to be undefined, right? Just because it's not actually
within scope at that point. But as we talked about in the
last example, because of closures, functions that are declared
have access to their variables
10:00 - 10:30 at the point of declaration. And so now right here
what is the value of i? Can anybody tell me? AUDIENCE: Five. SPEAKER 1: It's going to be five, right? Because we iterated through
the numbers 0 and 5. And by the time we got to 5,
that was where I was left. And since it was declared
with var, a var's lifecycle is basically until the function ends.
10:30 - 11:00 And so line 8 right
there, i has a value of 5. And so that's what gets wrapped
up in the closure at line 5. And so when we invoke line
15, it now prints out 5. Does that make sense to everybody? It's a little bit strange. It's hard to wrap your head around. But does that kind of makes
sense to why that's happening? So if we instead of using a var
here, because var's lifecycle
11:00 - 11:30 is from when it's declared until
the end of its function, so line 11. What happens if we instead use a let? So what is the scope of a variable
declared with the let keyword? Anybody remember from last lecture? AUDIENCE: [INAUDIBLE] SPEAKER 1: Yeah, exactly. It's until the end of the code block. And so this variable called
i, it ends at line 6. And so if we tried to console.log i
here, we get oh, it does not exist.
11:30 - 12:00 And so i for each time this four loop
runs, its scope is only from line four to line six. Therefore, this one, the closure
will actually work as expected. So when we run this, it
prints out a 0 as expected.
12:00 - 12:30 Does that make sense to everybody? It is a little bit weird. And I'm about to show you an
alternate way to create closures. But does this difference
in scoping make sense to why it would print
a five versus a zero? AUDIENCE: [INAUDIBLE]
Sorry, can I ask a question. SPEAKER 1: Of course. AUDIENCE: [INAUDIBLE]
12:30 - 13:00 SPEAKER 1: So the
question was, what happens if we add another variable
called i outside the four loop? Well, if we had one declared
with a let or const key word, line five would error because we cannot
create multiple let or const with the same names. If it were a var then it
would get shadowed by this one and basically be overwritten. Any other questions with this example?
13:00 - 13:30 AUDIENCE: [INAUDIBLE] SPEAKER 1: Ah, the
question is what happens if we create a i variable [? outside. ?]
So if we did let i equals sub number. Basically, the closure would wrap
up the most specific variable. So since this variable is more
specifically declared than the i outside, it would bind with this one.
13:30 - 14:00 So if we ran this, it prints a 0. Cool. So let's look at another
way to create a closure. So has anybody heard of immediately
invoked function expression? Or the term iife? I-I-F-E, for short. So, basically, what an iife is is
a function expression that gets
14:00 - 14:30 invoked immediately. And so this also creates a closure. Has anybody seen this
before or heard of it? AUDIENCE: [INAUDIBLE] SPEAKER 1: So the question was,
is it like a nameless function? In a way, yes. It's a nameless function oftentimes. But it's a nameless function
that gets invoked immediately. I'll show you what that looks like. And a benefit of using an iife
is that it doesn't add or modify the global object.
14:30 - 15:00 So we talked about last week how
when you create variables or create functions, those functions are
actually attached to the global object. But with iifes since
they're just statements that are immediately invoked, they
do not add to the global object. So let's take a look at
what those look like. So say we had something like-- so we in the previous
closure example, we
15:00 - 15:30 defined this thing called
a hello function, which was basically a function-- actually
let's just copy that directly. So we defined a make hello function
which had a message called hello which got wrapped in a closure
by the say hello function. And we returned that function. And so as part of a
global object we have this thing called make hello function.
15:30 - 16:00 Which might not be ideal if we are
running low on like names of functions that we can use. It's a way to basically create the
same closure without actually creating a globally scoped function is an iife. So let's see what that looks like. So the goal is to have a say hello
function which basically gets created by this make hello function
with a variable called message that gets wrapped in a closure. And so another way to do that
would be just saying const
16:00 - 16:30 say hello is equal to this function. And we can make it an
anonymous function. That's actually immediately invoke it. So does everybody see
what happened here? So we went from this where
it's make hello function. Which is declared as a function, which
you can use anywhere in your code, and then at line 11, we go
ahead and invoke that function
16:30 - 17:00 which returns that function
defined at line four which is a say hello function that
wraps that var message in a closure. But here instead we
don't create a function called make hello function, instead we
declare an anonymous function, which just gets invoked immediately at line 9. And so we're left with that same exact
function which is defined on line four. Where it's a function that
console.log as a message which
17:00 - 17:30 is defined by its parent function. But we don't actually have to
create that global function name. Does that make sense to everybody? And so if we ran this we
see the same exact thing. So why might an iife be useful?
17:30 - 18:00 I'll just delete these. So say we want to have some class
or something called a counter. And we want to keep track of some number
that we can just keep incrementing, and we can get that number. But say we also did not want that
number to be accessible to other people. How might we go about doing that? One way would be to use an iife. And so we can actually create that
variable within a very limited function scope that is non-accessible globally. And so doing that real quick,
we can create this thing
18:00 - 18:30 called a counter which is a
function where within here we create this variable called account. And we set it equal to zero. And then we can do something
like return an object where if we do something
like increment, it's actually a function which does
count equals count plus 1.
18:30 - 19:00 So it just increments that count. Or we can have a function
called get which just returns. Or let's just console log the count. So this creates a function but instead
we actually want that object back.
19:00 - 19:30 So we can actually wrap that function in
parentheses and immediately invoke it. And now we have an object that
has an ink and a get function. And we can go ahead and invoke those. So we can do counter dot get,
counter dot ink, counter dot get. And if we run that, we
can see it gets the zero, increments it, and then
prints out the one. But nowhere does any body have
access to that variable at line 12.
19:30 - 20:00 Because it's wrapped in that
function that nobody can access. Because its scope is limited
to lines 11 through 18. And the only things that have access to
that variable are the return functions. And so that that count variable is
not accessible in the global scope. Does that make sense to everybody? Do we see how that could be useful?
20:00 - 20:30 Any questions? So how might we be able to use
iifes to solve that closure problem from earlier? So let's copy that closure bug too. So we have this from
earlier which is buggy.
20:30 - 21:00 How might we use an iife
to solve this problem? The goal is now to print 0. Any thoughts? So what if instead of pushing a
function that consoles.logs i, we create a function that returns
a function that console that logs i and pass in i.
21:00 - 21:30 A little bit weird. So now we have a function
that returns a function that console that log something called i. Now what we can do is we can
immediately invoke that function with i.
21:30 - 22:00 Do people see how that creates
a closure by using an iife? So let's change a couple
of these variable names so that it's easier to see. So we're pushing onto that array. The result of a function that returns
a function that console.logs x. And what do we pass
in as x, we pass in i. And so that creates a
closure around that value
22:00 - 22:30 of x Which is then accessible
later on in the code. So if we go ahead and run this,
we get that 0 as expected. Any questions on that? Is that a question? It is a little bit crazy. This is not something
that you use every day. But this is something
that it helps to know.
22:30 - 23:00 Because you might see
things like libraries get imported by using an iife. So that a lot of variables that they
declare while creating a library don't pollute the global scope. All right. Moving on. So first class functions. So who knows what a
first class function is? Has anybody heard this term before?
23:00 - 23:30 So first class functions
basically describes the way that language handles functions. And so in JavaScript, classes are first
class citizens, people like to say. Or in other words, functions are
treated the same way as any other value. And so as we learned last week that
functions are really just objects. Everything that isn't a
primitive is just an object. So it really makes sense that functions
can be treated as other values. So functions can be
assigned to variables.
23:30 - 24:00 We've seen that when we
do something like const say hello equals some
anonymous function. They can be signed into array values,
which we saw with this previous example where we're pushing onto the
array anonymous functions. And they can be set as an object
values, which we saw in our iife example when we returned an object that
had an inc and a get function. They can also be passed as
arguments to other functions. There's nothing stopping us
from declaring a function which
24:00 - 24:30 expects a function as an argument. And what that does is it allows-- oh, they can also be returned
from functions as we saw earlier. In the previous example,
we saw a function that returned another function. And so it allows the creation
of higher order functions. So higher order function
is basically any function that takes one or more functions
as arguments or returns a function. And so some big examples of those
are map, filter, and reduce.
24:30 - 25:00 So does anybody have any questions
on what a first class citizen means or a first class function? We have seen almost all of these bullets
as examples in the past couple days. Cool. So has everybody heard of
map, filter, and reduce? Has anybody not? OK. So basically these are three of the
most famous higher order functions. What map does is it's an operation
that can be done to an array.
25:00 - 25:30 And what it does is it
maps a particular function, any function to every
single value in the array and then you get back an array
where the values in the array are the result of passing the original
values into some given function. What the heck does that mean? Well, it just happens to be that map
is already built into the array class. So if we create an array like const
x equals an array with 0, 1, 2, 3.
25:30 - 26:00 And say we create some
function called add 1. And takes in a number, let's
actually do this in node. So say we had an array with 0, 1, 2, 3. And we had a function called
add 1 which takes some number,
26:00 - 26:30 and it returns the number plus 1. And so if we do add 1 to 1, what
do we expect to be returned? Two. And how about if we did zero? We expect 1. 1 returns 2. 2 returns 3. 3 returns 4. And so if we were to map that function
to each of the values in that array, we should expect to have an
array that has 1, 2, 3, and 4.
26:30 - 27:00 And so if we do x dot map,
which is built into the array, if we passed in that
function called add 1, it basically maps that function
to each value in that array and returns the new one, the new value. And so as we expected 0,
1, 2, 3 returns 1, 2, 3, 4. Any questions on map? So what were the other two? Filter. So filter is basically
another high order function
27:00 - 27:30 where it expects a
function and this function that you pass in can either
return true or false. And basically what
filter does is it retains the values that return true and gets
rid of the values that return false. And say we have a function
called is greater than 1. It takes a number, and it returns
whether that number is greater than 1.
27:30 - 28:00 It returns whether that
number is greater than 1. So say we pass in is greater
than 1, a number like 100, we expect it to be true. If we pass in a number like
1, we expect it to be false. And say we were to filter that original
array 0, 1, 2, 3 by the function is greater than 1, what
do we expect to get back?
28:00 - 28:30 Is 0 greater than 1? No, so it shouldn't be included. Nor is 1. But 2, and 3 are. And so if we filter is by is
greater than 1, we get 2 and 3 back. And the last high order function that
we'll talk about it is called reduce. And basically what reduce does is
it takes an array of multiple values and reduces it into a single value. And basically what that does
is it takes a function that expects two arguments where the first
argument is some accumulator basically. It marches down each value and returns
that accumulator to the next value.
28:30 - 29:00 And the second argument is
whatever's next in that array. And so basically if we were
to define a function called add which takes in two
values and returns x plus y, we expect add 1 and 2 to return what? 3. And what would we expect
0, 1, 2, 3 to return?
29:00 - 29:30 AUDIENCE: 6. SPEAKER 1: 6. So if we do x dot reduce and
pass in add, we get back 6. Why is that? Because first it starts with zero. And basically it starts by
invoking the first two arguments. So it has zero and one. It invokes add. So 0 plus 1 is 1. It passes 1 on as the first argument. And y is the next value
in the array, so 2.
29:30 - 30:00 So we have 1 plus 2 is 3. And so for the next iteration, x is
3, y's is this next value called 3. It returns 6. And since that's every value
in the array, it returns 6. Does that make sense? So those are the three
higher order functions that we're going to talk about. And let's actually implement those. So in four higher order functions, let's
go ahead and declare some higher order
30:00 - 30:30 functions of ourselves. So let's do-- does anybody have a
preference if they want to do map, filter, or reduce? Let's do map. All right. So let's declare a function called map. And let's take two arguments. First, is the array that
we want to map over, and the second is some
function that we want to invoke to every value on the array. So can anybody give me a strategy on
how we might go about implementing this?
30:30 - 31:00 So first we're going to want
to create a brand new array. And then at the very end, we're
going to want to return that. Now what do we want to
do before we return? AUDIENCE: [INAUDIBLE] SPEAKER 1: Yeah. So the comment was first, we should
check if the array is an array and the function is a function.
31:00 - 31:30 I completely agree. But let's just assume that for now. So what does map do? It takes every value in an array
runs through some function, and returns another array
with the return values. So who wants to give me a strategy? Yeah. AUDIENCE: [INAUDIBLE] SPEAKER 1: Yeah.
31:30 - 32:00 So some sort of four loop that will grab
that value in the array and apply that function. Cool. So we can do four let's
use let i equal zero. i is less than however many
values that are in the array. And that's do that the
value just be array i. And then what we want to do is new
array push a value onto that new array.
32:00 - 32:30 And what do we want to push on it? The result of running that
function on that value. Does that make sense? Cool. So this would be absolutely correct. Unless somebody sees a bug. Shall we test it?
32:30 - 33:00 So we want to map over x, add 1,
and we expect to see 1,2, 3,4. And we do. Nice. And so one handy built
in function to all arrays
33:00 - 33:30 is this thing called a for each loop. So we could actually clean up our
code by using a for each loop. And so we could do the
original array dot for each. And what that does is it's a
higher order function itself that allows us to pass it a function. And it will invoke that
function on each of the values. So it's basically like map but
instead of returning a new array with those values, it just
invokes that function on those values without taking the return
function and putting it in an array.
33:30 - 34:00 And so we can say for each value here we
just push onto that new array the value after we run it through that function. Does that make sense? Cool. Any questions on the
implementation of map? Any questions on functions
as first class citizens?
34:00 - 34:30 Do you think it would help if
we implemented filter or reduce? Or are we good here? No? OK. Moving on. Cool. So you may have heard these
terms thrown around when dealing with JavaScript, things like
synchronous, asynchronous, single threaded. So what is JavaScript? JavaScript is actually single
threaded synchronous language.
34:30 - 35:00 And so since a synchronous is a function
that takes a really long time to run will cause a page to
become unresponsive. And we can actually demonstrate this. We can do this right now by
opening up our dev tools. And I'm going to actually cause
this website to stall out. So we can write a function called hang. And let's say for some
amount of seconds.
35:00 - 35:30 And basically what
this hang does-- oops. Let's override that
function called hang. And what it does is we can say const
done at is some time in the future. So date dot now which gets us to the
current time plus however many seconds
35:30 - 36:00 we want times 1,000. Because date dot now
returns milliseconds. And so now we have some value
called done at which is the time that we're going to be done. We can do while date dot now is
less than the time that we're done. Just do nothing. And so now everything is good.
36:00 - 36:30 As you can see, we can move
back and forth in the slide. But if I did hang for 10 seconds,
we're stuck for another 10 seconds until the page is done
with that [? what ?] loop. Well. Does that make sense? And this is because JavaScript is
single threaded and synchronous. And so since this while loop
was running for 10 seconds,
36:30 - 37:00 it was just doing while this
is true don't do anything. It's just going through that while
loop, it locks up the entire page. Yeah. AUDIENCE: [INAUDIBLE] SPEAKER 1: I believe so. So the question is if we did
something like while true, would it just lock up
the page permanently? I believe so. Unless the browser
protects against that. And I don't want to try because it
will take down the presentation. But as we just demonstrated, since
JavaScript is single threaded
37:00 - 37:30 and synchronous, while that
while loop was happening, we couldn't do anything at
all on that whole website. Which you could take advantage
of if you wanted to like have some malicious web site
which just does some while loop and locks up somebody's computer. But JavaScript also has some
functions that act asynchronously. And so let's take a look
at some of those functions.
37:30 - 38:00 So one of those functions
is called set time out. And we'll look into it a
little bit more in detail. But let me just show you how that works. So let's do a function
call a print 3 or print 1. And what that does is
it consoles logs 1. And let's it have a print 2.
38:00 - 38:30 And a print 3. And then if we invoked print 1, print
2, print 3, what would we expect to see? 1,2, 3.
38:30 - 39:00 But say we use this thing
called set timeout which is basically an asynchronous function. So say rather than printing 1,
we did set time out on print 1 to be a second, a 1,000 milliseconds,
or did set time out on print 2 with a time out of zero seconds. And then print 3 knowing
nothing about set time
39:00 - 39:30 out other than it set some time
out before running a function. What do we expect to be console logged? So what order do we
expect these to print? Anybody care to guess? 3, 2, 1. Why do you say that? AUDIENCE: [INAUDIBLE]
39:30 - 40:00 SPEAKER 1: OK, so 2, 3,
1 is the other guess. So let's actually just run this. And we see 3,2,1 even though set
time out for print 2 is zero. So let's dive a little bit
more into how this works. We we'll dive a little more into this
how this works in a couple more slides. But that's just a teaser
at asynchronous functions.
40:00 - 40:30 So how exactly can a language be
both synchronous and asynchronous. In order to explain
that, we have to explain these concepts called
executions stack, browser API's, function queue, and event loop. So let's dive deeply into
what an execution stack is. Has anybody heard the term
stack or execution stack? So functions that get invoked
by other functions get
40:30 - 41:00 added to this thing called a call stack. And we'll discuss a little bit
about more what that is in a second. And when functions complete,
they are removed from the stack and frames below continue executing. So does anybody or everybody
know what a stack is? So a stack is one of
those data structures that you may have seen in CS 50. And the example that we give for a
stack is something like a deck of cards
41:00 - 41:30 or a stack of lunch trays where
when you add things to the stack, they appear on the top. And so when you want to grab the
next thing, whatever you grab first is the most recent thing that
you've put onto the stack. So if you imagine a deck of cards, say
you have cards called 5, 4, 3, 2, 1, and you place 5, 4, 3, 2, and 1 on
the stack, the first thing that you get back is 1 and then 2, 3, 4, 5. As opposed to something like a queue
where it's like a line of people
41:30 - 42:00 where the first person in line is
the first person who comes out. And so let's explore what stacks are. Actually I'll show you in code
first, and then I'll draw it. So say we had a function called a. That just does console that log. i, a function called
b, that just calls a,
42:00 - 42:30 and a function called
c that just calls b. And then we invoked c. So can everybody imagine in their
head exactly what's going to happen? So c is going to get
invoked which calls b. b is going to get invoked
[INAUDIBLE] a, and a is going to console.log [? high. ?]
And so as you can imagine,
42:30 - 43:00 the JavaScript interpreter knows exactly
where which function gets added next. Actually a better example
would be something like we can use or add 1
function from above from earlier.
43:00 - 43:30 All right here's a little
bit of a better example. So when we invoke c, c is going to
console log, get numb plus get numb.
43:30 - 44:00 And so what is the value of get numb? So when you invoke the first get
numb, it returns add 1 of 10. And so it calls add 1, passes in 10, add
1 returns that original number plus 1. So it returns 11. Which returns to here,
which gets returned to here. And so somehow JavaScript has to know
that 11 is what get numb evaluates to. And then it does it again.
44:00 - 44:30 And so as you expect, this would
return a number [INAUDIBLE] console that log a number called 22. But let's actually go through
exactly how that works in drawing. So we have a function
called add numb or add 1. Which expects some numb.
44:30 - 45:00 We have a function called get numb. And we have a function called c. And what c does is it gets
two numbs and adds them. And what add 1 does is-- or what get numb does is it gets the
value of add 1 of 10 and returns it. So imagine we have this
mythical call stack. Which is basically the way that
JavaScript knows what's going on.
45:00 - 45:30 And so first, we invoke c. And so c gets added onto this stack. And so it's basically
JavaScript remembering like, oh, he called the c function. And what does the c function does? Well, it returns get numb plus get numb. And so in order to find out what
get numb is for the first time, we have to add get numb. We have to evaluate that. And so what is the value of get numb?
45:30 - 46:00 Well, we have to figure
out what add one of ten is. And so we need to evaluate that. And so JavaScript now
knows and is keeping track that we have to evaluate this thing
called add 1, and once we get it, it gets passed to this thing called
get numb, and once we have that value, it gets passed to c. And so this returns 10 or 11. So it returns 11 to get numb.
46:00 - 46:30 11 just returns that to c. And then what happens in c? Well, it needs to find
get numb plus get numb. So it has to evaluate get numb again. So get numb gets added to that stack. And how does get numb evaluate? Well, it needs to
evaluate get 1 or add 1. And so that evaluates. And after it evaluates, it
just gets erased from the stack because it's done. And then when get numb evaluates,
that also gets erased from the stack.
46:30 - 47:00 And then c console logs 22. And then c gets erased from the stack. Because that has finished executing. Does that make sense to everyone? Yeah. AUDIENCE: [INAUDIBLE]
like if one of the stacks creates a [INAUDIBLE] do
those variables [INAUDIBLE]??
47:00 - 47:30 SPEAKER 1: So the question is what
happens if one of those functions creates a closure? Does it still disappear from the stack? The answer is yes with an asterisk. So as long as nothing
else needs to remember all of those variables and stacks. So if these functions don't create other
closures then they'll just be erased. And you can just think
of it as being erased from memory because
that's really something that the engine itself handles. And you really don't have to
worry about memory and stuff.
47:30 - 48:00 But you can just think of it as
it just gets erased from the stack and from memory if no
closure is left around. But great question. Any other questions? Does this call stack
makes sense to everybody? Great. And so a quick demo of just
showing that JavaScript does indeed keep track of this call stack is
what happens if an error is found.
48:00 - 48:30 So if one of these functions ends up
creating an error, in this case add 1, and we run this, it
says, oh, no, an error which is the error that we created. And it says add 1 which was called
by get numb which was called by c. And so JavaScript does indeed
keep track of this call stack.
48:30 - 49:00 And you can see when
an error gets thrown, it basically dumps the
call stack to the console. Does that make sense to everybody? Any questions on call
stack, execution stack? Great. And so now going back to
asynchronous JavaScript. So how exactly does this thing
called set time out work? How does it not just
immediately get invoked?
49:00 - 49:30 How does any asynchronous things work. And in order to
understand that, you first need to understand execution stack. And then I can talk
you through exactly how things get handled in terms of browser
API's, function queue, and event loop. Let's go ahead and draw
that on the board as well. So this thing here we
can call the stack.
49:30 - 50:00 And this is basically
exactly the same stack that we were talking about before. Over here we can call this API's. Basically these are
functions that you can call that are not directly
built into JavaScript but might get run in the browser. We have this thing we can draw down
here called the function queue.
50:00 - 50:30 And we have this thing
called the event loop. So basically we talked in depth
about how that stack worked. But we have not mentioned API's,
event loop, or function queue. So basically what API's are
these things like set time out or fetch or any of
these other asynchronous
50:30 - 51:00 functions which get run
and handled by the browser but not necessarily
by JavaScript itself. And so say we had something-- does
everybody remember the example from before with print 1, 2, and 3? Let me remind you of
the code real quick. So we have print 1, print 2, and
print 3, are our three functions that we defined. And we set time out print 1 to 1 second,
set time out print 2 to zero seconds,
51:00 - 51:30 and then print 3 immediately. And so when this file gets
executed, three things happen. First we call print 1. But set time out for 1 second.
51:30 - 52:00 Then we do the same thing
with print 2 for zero seconds, and then we'd call print 3. And so basically set time out
of print 1 for 1,000 seconds gets tossed on the stack here. And set time out is actually one
of those asynchronous functions that gets handled by the browser. And so that gets tossed over here. And so that's print 1 in one second.
52:00 - 52:30 And so the browser
actually is the thing that handles keeping track of the seconds
until print 1 should get executed. And then the function queue says, OK,
I executed that line of code, I'm done. Next is set time out of
print 2 for 0 seconds which gets thrown on here,
that gets evaluated, and that's handled by the browser as
well since it's a set time out call. So this gets print 2 with
a time out of zero seconds.
52:30 - 53:00 And then the next line
of code in the file was print 3 which immediately gets
tossed on the queue or on the stack, and it consoles that logs 3. And so 3 gets consoled out logged. And then the state of the
world is basically this.
53:00 - 53:30 Because all of this happened
in very, very quickly. Is everybody with me so far? And so now the browser says,
hey, it's been zero seconds. It's time to call print 2. And so this gets put
in the function queue. And so as we alluded to
earlier a queue is basically a line where the first
things that get added are the first things that come out. And so it says print 2 is ready.
53:30 - 54:00 And that gets erased from here. And so now the state
of the world is this. There is nothing on the stack because
that file has finished executing. It did set time out of print 1 1 second. It did set time out of
print two for zero seconds. And it did set print 3 which
immediately console log 3.
54:00 - 54:30 And so now the state
of the world is this. There's nothing on the stack. There is one thing in
the function queue. And there's one thing
over there called print 1, and the browser is
keeping track of the time. And so there's this thing called the
event loop which it just constantly checking. First, is there anything on the stack? If there's something in the stack,
just keep doing what you're doing. Finish the stack. But once the stack gets
emptied, it says hey, is there anything in the queue
that's ready to go onto the stack? And now there is. The stack is empty. And there's something on the queue. Until the event loop says, hey,
let's move this into the stack.
54:30 - 55:00 And so the event loop takes care
of moving print two onto the stack and erases it from the queue. So now the state of the world is this. There's something on the
stack called print two. Function two is empty,
and the browser is still keeping track of when it should print 1.
55:00 - 55:30 And this is basically
still 1,000 milliseconds. So now it's good, what happens? Since there is something on the
stack that always gets the highest priority, since we know
JavaScript is synchronous, it's just going to execute
everything on the stack before even looking anywhere else. And so since there's something on the
stack called print 2, it executes that. What does it do? It prints out 2. And then says, OK, I'm
now done with the stack.
55:30 - 56:00 And so now this is the
state of the world. There's something over there being
tracked by the browser called print 1. It still has 1,000 milliseconds
or so on the clock. There's nothing in the stack. And there's nothing in the queue. And the event loop is saying,
oh, there's nothing for me to do. So now what happens? Well, basically nothing
for a whole second. So basically this timer runs down. And as soon as this hits zero,
can somebody tell me what happens? AUDIENCE: [INAUDIBLE] SPEAKER 1: Yeah.
56:00 - 56:30 So print 1 moves to the queue. So as soon as this hits 0,
this gets moved down to here. So now we have print 1. This gets erased. And now what happens? AUDIENCE: [INAUDIBLE] SPEAKER 1: Exactly. The event loop says,
hey, the stack is empty.
56:30 - 57:00 But there's something
on the queue, so let me move that up to the
queue or the stack I mean. Move the thing from
the queue to the stack. And so now print 1 is here. Gets erased from the queue. And then what happens? Print 1. And then the stack is cleared.
57:00 - 57:30 And now we're done. There's nothing left
being tracked by the APIs. There's nothing left in the stack,
and there's nothing in the queue. And so what happens at the
very end, well, we print 3,2,1. Does that make sense to everybody? Yeah. AUDIENCE: [INAUDIBLE] whereas
everything that is on the [INAUDIBLE]
57:30 - 58:00 which it appeared there? SPEAKER 1: Yes, exactly. So the question was about
ordering, and how is order affected when things are on the stack? Queue and the APIs. Over there. And the answer is exactly as you said. Everything in the stack
has a definite order. Things at the top get executed
before things on the bottom. And same things at the queue. Things get queued up. And as soon as the stack
is empty, whatever's
58:00 - 58:30 next in the queue is guaranteed to
be in the next thing on the stack. And if that thing calls
other functions, the stack will grow and shrink
before even grabbing another function from the queue. And then things in the
APIs over here, these you have no real guarantees on what
order they're going to return in. And so that's what the asynchronous or
the concurrency of model of JavaScript is. It is basically these APIs
are handled by the browser. And they will basically let
the rest of the JavaScript
58:30 - 59:00 know when they are done by pushing
things onto that function queue. And then as soon as they're
on the function queue, then you have a guaranteed
order when they're going to get put onto the stack. Does that make sense? AUDIENCE: So if you set time
out on three different things for the same amount of time,
is there a guaranteed order? SPEAKER 1: So the question is if you
set time out three different things is there a guarantee in order? I believe so. So if you do set time out of print
1, 0, set time out of print 2, 0,
59:00 - 59:30 set time out of print 3, 0, I believe
you're guaranteed to print out 1,2,3. But the caveat is that it depends
on the implementation of the API. So it really depends on
the browser you're using. But I believe browsers
will have that guarantee. Any other questions? Yeah. AUDIENCE: For the event loop, you
said it starts with [INAUDIBLE] So
59:30 - 60:00 like that's just whenever [INAUDIBLE] SPEAKER 1: Exactly. So what the event loop
does is it basically checks when the stack is empty. It moves something from
the queue to the stack. And that's all it does. Is it's just constantly checking,
hey, is the stack empty? If not, then I'll wait. Is the stack empty? Oh, now it is. Is there anything on the queue? Oh, there is.
60:00 - 60:30 So let me move it to the stack. Yeah. AUDIENCE: Is there a limit to the queue? SPEAKER 1: Is there
a limit to the queue? AUDIENCE: A realistic limit? SPEAKER 1: Is there a
realistic limit to the queue? No. The limit to the queue is basically
what can be held in memory. And so what happens if
we run out of memory? Let's have an example that does that.
60:30 - 61:00 So this won't actually
overflow the queue. But this one will overflow the stack. So we have a function called recurse. And recurse let's console that log,
recursion, and then return recurse. So what do we expect to happen here?
61:00 - 61:30 Yeah. So recurse is going to
console long recursion. And in return, the
return value of recurse. What's the return value of resurce? Well, it's recurse is return value. And so we're going to keep
going down that rabbit hole until we run out of stack. So if we run this, oh,
maximum call size exceeded. Because if we scroll-- I'm actually scrolling. There are a lot of these, a lot of them.
61:30 - 62:00 So that's what happens when
we run out of stack size. Cool. Any questions about the
asynchronous JavaScript? So what are some examples of
asynchronous functions in JavaScript? Well, we saw set time out. I alluded to this thing
called fetch which is the way of fetching network requests.
62:00 - 62:30 JQuery, if you've ever
used it, it has a lot of asynchronous functions for
fetching things like Ajax. EXML HTTP request which
is built into the browsers for fetching things,
things like database calls. Anything really that relies on
something other than the JavaScript is going to be asynchronous. Cool. So what happens if we want something,
say we have some asynchronous call, and we want to do something with
the return value of that call. How might we do that?
62:30 - 63:00 Well, we could just wait for it to come
back, but that wouldn't be really great would it? If say we have some web
site which is what's shown is relying on some
database call, we don't want to like lock up the entire web site
until that database call comes back, right? That wouldn't be very good for the user. The analogy there would be say you
wanted to hang out with your friend, and you call him, and you say,
hey, let's hang out, and he says, oh, I'm at work, I'll
be done in five hours. You don't say, OK, and then just
sit there for five hours, right? You go ahead and do other stuff.
63:00 - 63:30 And then five hours later, you say,
oh, my friend is done with work, now let's go do something. And so that's exactly how JavaScript's
concurrency model or asynchronous model works, is this thing called callbacks. Callbacks are the way that you
control flow with asynchronous calls. Or in other word, you
execute some function as soon as some asynchronous
call returns a value. And what that means
is the program doesn't have to halt and wait for that values. You don't just sit there until
your friend is done with work. You go do other stuff,
and when he's done then
63:30 - 64:00 you say, OK, now let's
go hang out or something. Does that make sense? You want to see this in action? So let's have this function
which takes a callback.
64:00 - 64:30 Well, first let's just
do something and then-- so function do something takes a
callback and console logs the result of invoking that callback on 1.
64:30 - 65:00 So what type is that call back? It must be a function, right? If it's getting invoked. And so do something is basically
a higher order function like we discussed earlier, which
takes as an argument some function and will invoke it with 1. And so say we did do something,
let's not even console log.
65:00 - 65:30 Let's just invoke it. And we pass it into do
something console dot log. What would happen? Well, we passed in this function
called console dot log to do something. And then at line 2, we invoke
console dot log with 1. And so we expect this to console log 1. But say do something was
actually an asynchronous call.
65:30 - 66:00 Say rather than invoking the
callback on 1 immediately, it did set time out for some
number of time, one second. And set time out takes a function
that immediately invokes. So we'll just create an anonymous
function that invokes callback on 1 in one second. Now it's not do something, but
rather it's do something async.
66:00 - 66:30 Now what do we expect to happen? Well, one second later,
it console logs 1. And so this is an example of a callback. So we have some function that
does something asynchronously. In this case, it returns 1
basically a second later.
66:30 - 67:00 I mean how do we control what we
are going to do with that value soon as it returns? Well, we just pass in a
function that says, hey, we know that this
asynchronous function is going to return some value eventually. And so let's just pass
it a function to handle what we're going to do with that value. And so with do something
async, what we're doing is we're passing in a function called
console dot log, and what we do is we console dot log the return
value of the async function whenever it decides to return.
67:00 - 67:30 And so for things like
network requests where we don't know exactly how long it's
going to return, what we do is we pass in a function that handles
the eventual return value. And so as soon as that
network request comes back, then we have the function
that will say, oh, I know what I'm supposed to do with
that network request let me do it. Does that pattern make sense? Any questions on callbacks?
67:30 - 68:00 Great. Let's look at an example with callbacks. A real life example taken from some
code that I've actually written. So from personal project of mine,
I have this function called log in. And what log in does is it has a
whole bunch of asynchronous functions. So log in takes a request and
a result and some callback. And so what we're doing basically
is we're looking for the user by their email.
68:00 - 68:30 This is an asynchronous function. And we're passing in a callback with it. And this callback takes in
an error, if an error occurs, and the user, if the user exists. And if there's an error, we
return this original callback. It says, hey, there's an error. Let me handle like that. Otherwise, there's a
user that came back. And so let's do this user dot compare
password which is asynchronous. And so we need to pass in a
callback function with that. And that callback function is here. And so either there is
an error or it matches.
68:30 - 69:00 If there's an error, handle that error. If there's not a match,
say, oh, incorrect password. Otherwise, create this token
and then sign that token which is another asynchronous function. It takes a callback which
expects and error and a token. If there's an error we handle the error. Otherwise, we handle that
token, save that user, which is another asynchronous function. And so the callback takes the error. If there's an error, handle it.
69:00 - 69:30 Otherwise, return. And now we're waiting nested into
this what is known as a technical term callback hell. Basically callback with a
callback with a callback with a callback and another callback. And so that there is
called callback hell. We see this that kind of
looks like a Christmas tree. If you've ever seen there are some
pictures online of callback hell where it's like 10 20 iterations deep. And you see basically this
Christmas tree of code.
69:30 - 70:00 And that there is the downside
of callbacks within callbacks. And we're going to
take a short break now. And after the break, we'll look at some
ways of combating this callback hell. All right, welcome back. Before the break, we were
showing this function that I wrote on a
personal project of mine demonstrating this thing that
we called call back hell. That is callbacks within callbacks
within callbacks recursively. Which gets a little bit
messy and hard to read. And I alluded to this
thing that we could use to alleviate callback
hell which is promises.
70:00 - 70:30 So who here has heard
of a promise before? Who here has heard of a
promise in real life before? Hopefully, everybody. So what's a promise in real life? It's basically you telling
somebody that you're going to do something
eventually, and they can just have your word that you are
going to do it eventually, right? And so that kind of seems like the
asynchronous model of JavaScript. Whereby you basically
get some sort of promise that something is
eventually going to happen.
70:30 - 71:00 And so JavaScript also has this
object called a Promise, capital P, whereby you can alleviate
callback hell by writing code that assumes that a value is
going to be returned eventually with the access function. And a big upside about Promises is that
you only need a single error handler. And so we saw with the
callbacks' example over here, we see line 15, if there's
an error return this. If line 8, if there's an error handle
it, line 5, if there's an error
71:00 - 71:30 handle it. Like 19, if there's an error, handle it. And with Promises what we have-- a big advantage of
promises is that we don't have to handle the error
within every single callback. We can just do it once and be done. So let's go ahead, and let me
show you how Promises work. So say we have some function
that returns a Promise. One of those functions is called fetch. And we'll talk about fetch
in depth in a few weeks.
71:30 - 72:00 But just take my word for now
that fetch returns a Promise. So we could do something
like fetch some URL. And then we know that
fetch returns a Promise. And eventually it's going
to return to us this URL. So we can start to do
is write a function that expects the response to come back
and start handling it already.
72:00 - 72:30 And the way you would
do this with a promise is this thing called dot then
which takes a callback itself. So we could have a callback
that takes the response and does something with it. If we want it to then handle that
later, we can chain a dot then that takes whatever, some JSON
maybe, and does something with that.
72:30 - 73:00 And maybe if we wanted to do
something with that JSON dot later, we can do dot then again. Do something with that. So on. And we can just keep chaining
these thens as long as we want. And so this is basically the
same as putting a callback within a callback within a callback. But as you see, we don't keep creating
this Christmas tree of callbacks. Rather we just chain a new dot then. And we don't actually have to
worry about handling an error here.
73:00 - 73:30 Instead, what we can do is a dot catch. And this catch function
down here will actually handle any errors that get thrown in
any of the preceding then statements. And so we could handle the error here. And we would not actually
have to do it in any of the then statements over here.
73:30 - 74:00 And so something that you might see,
we'll discuss this in later lectures. But you might see something
like return res dot JSON. Which is basically saying extract
the JSON out of this result. And here you might be doing something
like return only the important parts of the data maybe. We could do like important
data is JSON dot important.
74:00 - 74:30 And so on. And maybe down here we eventually
want to just console dot log it. And so this would be an
example of using a Promise rather than using callbacks
within callbacks within callbacks. And so let's actually
refactor my old authentication code to use these Promises.
74:30 - 75:00 So here we have a bunch of callbacks. And one thing that we know
is that we don't actually have to handle any of the errors. So first thing that we do is
we're going to do user dot find 1. So basically this.
75:00 - 75:30 And so before let me show
you a before and after. Before we had this
function called user dot find 1 which takes in basically
the query that we're looking for as well as the callback function. But rather than passing
in a callback function, we can actually, since
this does return a Promise, we can do a dot then that has a
callback function which expects a user.
75:30 - 76:00 And so we've started to
start refactor line 5 here. So rather than passing
a callback function that takes an error in the user, we just
do a dot then that handles the user. And how do we handle the error? Well, we just have a
dot catch dot error. And what have we been doing with that? Well, if there's an error, we
just return callback error. So we can do that in the
[? catch lock ?] there.
76:00 - 76:30 And now we're done handling errors
for the rest of the Promise. And so we can get rid of line 11. You can get rid of line 17. And we can get rid of line 20. Now we can get rid of 10 since
we already refactored it out. Then what do we do with that user? Well, you can cut and
paste that into there. So we want to compare the password. And compare password takes in a
password as well as a callback. And so let's go ahead and return that. And then handle that callback
with another then instead.
76:30 - 77:00 And so rather than having a callback
that expects an error and is a match, we can just only handle
that is match case. And so what do we do
if there's not a match? Then we want to tell them there's
an incorrect password in return. Otherwise, we want to
take what the payload is
77:00 - 77:30 and return this new
[? jot ?] sign Promise. So let's do this. Copy and paste this. Get rid of that callback which
expects an error and a token. And, instead, return that, and
handle that in another then.
77:30 - 78:00 What did we expect? We expected a token. And what do we do? We do this. And user dot save, it looks like
it takes another callback which
78:00 - 78:30 is only looking for the error. So we could return user dot save. And then, finally, do that. And then we get to get rid of
all these closing curly brackets.
78:30 - 79:00 And that there is our new login function
with Promises rather than callbacks. Did that refactor make
sense to everybody? And does this Promise structure look
nicer than the callback structure? This is something we're going to
go into a lot more depth in when we talk about data in a few weeks.
79:00 - 79:30 But do Promises in general
make sense to people? Yeah. AUDIENCE: [INAUDIBLE] SPEAKER 1: So, yeah the question
is how does the catch function know when to get invoked basically? And basically this is
all so user dot find
79:30 - 80:00 1 dot then dot then dot catch is all one
big basically Promise handling chain. And promises, which are
built in, know exactly what to do when an error is found. So if an error is found, it'll
just march down that chain until it finds a catch statement. And then it will invoke that
callback with that error object. AUDIENCE: But that's not [INAUDIBLE] SPEAKER 1: And it stops
future thens from happening.
80:00 - 80:30 Any questions on promises? Again, we'll dive more deeply
into them in coming weeks. Yeah. AUDIENCE: So a Promise
is a good solution for all the bad stuff what comes with
callbacks where what is the trade off? What can you do with this that
[INAUDIBLE] you still have to go back to callbacks [INAUDIBLE]? SPEAKER 1: So the question
is what's the trade off between callbacks and Promises? And what, if anything, do we lose
when using Promises over callbacks? The answer is not really much.
80:30 - 81:00 Most things are migrating from the
callbacks of the past to now Promises. But Promises were something
that were introduced fairly recently to JavaScript. Which is the reason that callbacks
still exist a lot in legacy code. And so what is the future? So right now, Promises are very popular. But there's a new way of handling
asynchronous things that's coming in the future. So there's this thing called AsyncAwait
which is actually introduced in ES 2017
81:00 - 81:30 which is the next, next maybe. So ES 2017 has been finalized. But it's still not
adopted by everything. But AsyncAwait is included
in that ES 2017 spec. And it allows people to write async
code as if it were actually synchronous. And so we're not going to
dive too deeply into this. But I thought I could just
show you quickly a refactor of what we've done so far to use this
AsyncAwait rather than the Promise syntax.
81:30 - 82:00 So right now log in is
a big Promise chain. And if we refactored it using
this new AsyncAwait syntax, we can actually make it
look very synchronous. So first thing that we need
to do is add an async keyword
82:00 - 82:30 to the function which is letting the
JavaScript interpreter know, hey, this function is async which
means handle it appropriately. Which is basically
what it does is allows us to use this other key word called
await which will functionally just wait for a value to come back
before continuing the code. But it does this
asynchronously behind the hood. So basically what user dot find
1 dot then function user is doing is waiting for a user dot find 1
to return with some value, which
82:30 - 83:00 is going to be that user. And so if we were
writing synchronous code, we might do something like const user
equals the value of user dot find 1. And if we were using
AsyncAwait syntax, we could basically do that by saying
const user is user dot find 1. But we know that user dot find 1 is
actually an asynchronous function. So we actually have to just wait
for that response to come back. And so if we use that
await keyword, it's basically saying, hey, wait
for that result to come back.
83:00 - 83:30 But don't actually just
like stop and wait, just wait behind the scenes asynchronously. And so what might we want
to do, well, then next we want to do user dot compare password
which gives us this thing called is match, and so if we're
doing this synchronously, we might do something
like const is match equals await user dot compare password.
83:30 - 84:00 body.password. Then this is basically
asynchronous code, right? We can do if it's a
match, do this and return. Otherwise, create this payload. And then sign dot jot which
will give us a token back.
84:00 - 84:30 But since this is an
asynchronous function, we have to use that await key word. Then what? Now we have the token,
so let's do these things. And rather than returning user dot save,
which is what we would do in a Promise, well, we just want to make
sure that it succeeded. So we can do const success equals that. And as long as that works,
then we can go ahead
84:30 - 85:00 and do res dot JSON with that token. And now we're basically done. What's one thing that
we haven't handled? The case where one of
these things errors. And so we haven't talked
about this before, but JavaScript actually has
this thing called try catch which allows us to try to do some code. And if an error happens, intercept
that error and handle it in code
85:00 - 85:30 rather than delegating to
the browser's error handling. And so what we can do is we can actually
wrap all of this logic in a tri lock and catch any errors and
handle those appropriately. Which is basically by invoking the
callback that's passed into this login function with the error. We're done with error handling, and
we can just style this appropriately.
85:30 - 86:00 And so now with this
new AsyncAwait syntax, we can write async functions
in a more synchronous manner. But everything behind the hoods
is still running asynchronously. Oops. One thing we forgot to
do is await this value. Any questions on this syntax? Again, this is something that
will dive more deeply into as soon
86:00 - 86:30 as we get into actual data
handling in the future. As a random poll, who prefers callbacks
over everything we've seen today? Who prefers Promises? And who prefers AsyncAwait? About 50-50 actually. Cool. Noted. And people online do just
drop something and slack, and I will take your votes into account.
86:30 - 87:00 Cool. So let's pivot a little bit
from asynchronous actions and talk about this. And by this, I literally mean this. So who here has seen this keyword
called this in JavaScript before? Who here seen this in other languages? So this in JavaScript is slightly
different than other languages sometimes in confusing manners. But, hopefully, by the end of this
lecture, it will not be confusing. So this basically refers
to an object that's is
87:00 - 87:30 set at the creation of a new
execution context or in other words a function invocation in other
words another stack frame on that stack that we drew earlier today. And in the global execution
contests, or basically the window console or the node REPL or
the function that gets invoked in node, it refers to a global object. And if a function is called as a
method of an object, or in other words,
87:30 - 88:00 a method is basically a term for
a key value pair in an object where the value is a function. That key is considered a method. So if a function is called
as a method of an object, this is bound to that object
that function is called on. So what the heck does that mean? Well, so let's just demonstrate in node. If we just type this, we get
back that big global object.
88:00 - 88:30 In the browser console, if we type
this, we get back that window. So as we discussed last week,
we saw that window was indeed the global object in the
scope of the browser console. And how might we write something such
that this gets bound to other objects?
88:30 - 89:00 So let's write 12 this. Cool. And so I mentioned that if a function is
called as a method of an object, this, is the key word this, gets bound to the
method that the functions is called on, or the object that the
method is called on. So let's just create some objects. So let's do const person
is somebody with a name.
89:00 - 89:30 And let's have a function called greet. So in line 3, I'm using this
thing called this dot name. And this is part of a function which
is defined as a method on this object.
89:30 - 90:00 Remember, a method is just a key
where the value is a function. And so in this case, person dot
greet is considered a method because greet is this function. And so if we call person dot
greet, this gets bound to person. And so this dot name becomes the value
of person dot name, which in this case is Jordan. So if you were to run this, we
see Jordan [? Gifts. ?] Printed.
90:00 - 90:30 Let's make this more of
a greet by doing hello. Then we see hello, Jordan. But what happens if we want
to do something like this?
90:30 - 91:00 What might we expect
to happen in this case? So we declare this global
const called greet. Global meaning it's
outside the other object. And we set it equal to person dot greet. And so, basically, greet
right now is a function that console dot logs
hello this dot name.
91:00 - 91:30 So what is this in that case? So first we have to find where
is this function getting invoked? That's at line 10, right? It gets defined at line 8, but
it gets invoked at line 10. And so what is the value of this here? AUDIENCE: It's a global object? SPEAKER 1: Yeah. It's a global object.
91:30 - 92:00 And so what is the
value of this dot name? AUDIENCE: [INAUDIBLE] SPEAKER 1: So yeah, name is not
actually a key on that global object. And so if we try to de-reference a
key that doesn't exist on an object, we get undefined. And so if we do this, we're
going to get hello undefined. Does that make sense?
92:00 - 92:30 But what if we were to create
some other object called student? Let's call it friend. I mean a friend has a different name. But their name is David. And how if we did something like friend
dot greet equals person dot greet.
92:30 - 93:00 So now what do you expect to happen? So where does greet in
this case get invoked? Line 14. And what is it getting invoked on? Right now it's a method
of another object, right?
93:00 - 93:30 And so what I object is that? Well, that's friend. And so what does this get bound to? It gets bound to friend. And so what is friend dot name? In this case, it should be David. So let's try running this. And we get hello, David. Does this make sense?
93:30 - 94:00 So now-- Yeah. AUDIENCE: [INAUDIBLE]
really explicit and instead of saying this you could have
just referenced to context as you are typing you know
what the developing context is. So is this should it be thought
of just a useful short cut or? SPEAKER 1: So the question
is for the camera, is this should it be thought of
as some sort of useful shortcut?
94:00 - 94:30 In a way, yes. It's a way of using a variable. And we don't yet know exactly what
that variable is going to be bound to. Because in the case of person,
we know that this dot name is going to be equal to that person. But that's not always the case, right? As we saw if we take this greet method
on person and assign it to friend, this dot name is not person dot name. In that case, it's going
to be friend dot name. And so it's kind of a way of
using a value that we don't yet
94:30 - 95:00 know what it's going to be until we
go ahead and invoke that function. And when we start handling
events and stuff and react and stuff like that, we will see or even
react components and stuff like that, which is coming in the
next lecture, we'll start to see exactly why this, a
key word called this, is useful.
95:00 - 95:30 Cool. And now let's do a challenge together. Let's try to get line
18 to greet somebody. How might we go about doing that? So what does this greet function do?
95:30 - 96:00 This greet function just does
console.log hello to this dot name. And so we need to figure
out some sort of way that when line 18 gets invoked, that
this dot name is bound to some variable that we want. So there are a few
different ways to do this. Let's see if we can
figure one out together. Yeah. AUDIENCE: [INAUDIBLE] SPEAKER 1: Yeah. One way is we could put the name
property on the global object.
96:00 - 96:30 So we could do something
like do you think it matters whether I do it on line 15,17, line 1? Where should I put this? AUDIENCE: [INAUDIBLE]
global object [INAUDIBLE] SPEAKER 1: Yeah. So the answer is yeah. It doesn't matter where I declare this. Because as long as it happens before
line 18, this dot name will exist.
96:30 - 97:00 So I could do something like
this dot name equals Johan. Who is one of our teaching assistants. And line 20 would now say hello Johan. Actually there's a small caveat here. The way that node evaluates
files, it actually won't work if we just invoke
this by doing node 12.
97:00 - 97:30 It's still going to be undefined there. That's just I'm going
to wave my hand for now. It's the way that node handles
invoking files under the hood. But if we actually did this in
the node console right here, if we did const person equals
name greet is the function. Just console logs hi.
97:30 - 98:00 So if I did person dot greet here,
we see hi, Jordan as expected. And now if we did something
like const greet equals greet.
98:00 - 98:30 We call greet there, we see
hi undefined as expected. And now if we did something like
this dot name equals Johann. Now if we did greet, we
see hi, Johann as expected. Why? Well, because if we do this, we
see that this has a key called
98:30 - 99:00 name which is equaled to Johann. Does that make sense to everybody? Again, I'm going to wave my hand at the
why this doesn't work in the node the execute a file, but it does indeed work
if we try to do it in the node REPL, or if we want to do it in the
browser console, it would also work. m. So I mentioned that there are other
ways of setting this manually. And there actually are.
99:00 - 99:30 So there's these functions
called bind, call, and apply. And all of these take
at least one argument where the first argument is explicitly
what you want to set this to be. And so if we were to go
back into that example, and here we wanted to
do if we deleted this, and we did const greet equals person
dot greet dot explicitly bind,
99:30 - 100:00 we can define some any
object that we want here, and that's what we'll get bound to
the this in this particular function. So if we did bind it
to some object where the name is this is a bound
object then if we ran this, we would see hello,
this is a bound object. Because we are explicitly bound
the this in this particular function to be this particular object.
100:00 - 100:30 Does that make sense? And the difference between
bind and call and apply is that call and apply rather than
returning a new function because person dot greet dot bind returns
a new function where the this is automatically
bound, call and apply will immediately invoke that function. So rather than doing const greet equals
that if we wanted to use call or apply,
100:30 - 101:00 we'd would do just person dot greet dot
call and then pass in something there. And same thing with apply. That makes sense? So say we wanted to do this, we would
see all three of those got bound. The difference between
bind call and apply is that bind returns a new
function which we store in greet,
101:00 - 101:30 and invoke greet later, and call and
apply just immediately invoked that. Does that make sense? So one other way to set this manually
is by using ES 6 arrow notation. So ES6 arrow notation
will actually bind this to be whatever this is at the
time that we declare the function, rather than at the time
that we invoke the function. And so if we did const person const
new person is somebody with a name
101:30 - 102:00 and greet is this new
arrow notation, which we'll talk about or show many
more examples in the days to come, and did consol dot log this dot name.
102:00 - 102:30 If we did new person dot greet here we
see what is this dot name at the time that we actually write this here.
102:30 - 103:00 What is the value of this? Again, this is a weird node thing. If we did it in the command line, if
we did const new person equals name new person is undefined.
103:00 - 103:30 And why is it undefined? What is this at the time
that I was typing this? AUDIENCE: [INAUDIBLE] SPEAKER 1: It's the global object. And what is this dot name is undefined. And so ES6 the arrow
notation will actually bind this to be whatever the
value is at the time of writing.
103:30 - 104:00 Any questions on this? Cool. So now let's talk about something that
will be important in the assignment. So browsers in the DOM. So how many people have
heard of the DOM before?
104:00 - 104:30 Most people. It stands for Document Object Model. And it's basically this
tree like structure that the browser maintains in
order to be in sync with what the HTML of the page declares. And so say we had some very
simple HTML file which was just something like HTML, it
had a head with a title, it had a body with H1 and a paragraph. This can be expressed in sort
of a tree like model, right?
104:30 - 105:00 We have the document, we
have inside the document we have some HTML, what's inside the HTML? Well, we have a head,
and we have a body. What's inside the head? Well, we have a title. What's inside the title? Well, it's some text called
this is a simple page. What about the body? Well, we have an H1,
and we have a paragraph. And what's inside those? Some text as well. And so we can sort of describe
that as a tree, right? We have at the very top a document,
and below that we have some HTML.
105:00 - 105:30 And what was inside the HTML? We had a head and a body, right? So had a head and a body. And what was inside
the head and the body? Well, the head had a title. The body had a couple other
tags, H1 and a paragraph.
105:30 - 106:00 And so we can sort of describe those
also as part of the tree, right. So head there's a title. Body had an H1 and a paragraph. And those each had some text. And so do you see how that HTML
maps onto some tree like structure that we can maintain? So this tree like structure is called
the DOM or the Document Object Model. And it's the way of modeling the HTML
that is rendered onto a web page.
106:00 - 106:30 Does that make sense to everybody? And so why does that matter? Well, we can actually modify
that DOM using some JavaScript. And as we'll discuss
in section this week, we'll discuss exactly
how you might do that. And that is exactly what the first
project is going to be covering.
106:30 - 107:00 So in the first project
which will be released today, you will create a to do app. And so the to do app
will basically be a way of tracking some to dos
that you'll have to do. And you all use JavaScript
and DOM manipulation in order to create and track however
many to do's you need to check off. There'll be specifics
coming out via email. But this assignment will be
due in a couple of weeks. And sections will also
be starting this week.
107:00 - 107:30 You should have gotten
email before class today with a form about
a couple sectioning times and if those work for you. And those sections will
be starting this week. And sections are basically 1 and
1/2 hour, 1 to 1 and 1/2 hour block where led by one of
our TAs, Johann or Raylen, will be talking about smaller stuff
that we didn't quite cover in lecture. One of these topics will be DOM and
manipulating the DOM using JavaScript. And so this week, they'll be talking to
you about that, answering any questions
107:30 - 108:00 that you may have. And then preparing you
for this first project. All right. Let's call it for tonight. And I'll stick around for some
questions if you have any after.