[MUSIC PLAYING]
DAVID MALAN: All right, welcome
everyone to Mobile App Development
with React Native.
My name is David Malan,
and this here is--
JORDAN HAYASHI: Jordan Hayashi.
DAVID MALAN: --and this
is a course that assumes
as background only
something like CS50, which
is Harvard's Introduction
to Computer Science.
But more generally, if you haven't
taken that particular course,
prior programming experience in
most any language should suffice.
The focus of this class, of course, is
going to be on mobile app development.
And the interesting
thing about this space
is that it's been
changing pretty rapidly.
It wasn't all that long
ago where none of us
actually had smartphones in our pockets.
And so the landscape has been
changing, particularly quickly.
And it's getting better and better.
If you've done any app developments on
mobile devices or any web development
on mobile devices,
early on we pretty much
just had HTML and CSS, maybe some
JavaScript for interactivity.
Then lots of libraries
came onto the scenes.
They, via CSS and JavaScript,
gave the appearance
that you had a mobile-like
application on your phone,
but the user interface
wasn't all that good.
And you can tell that this
isn't really "native".
That is, code that's in Objective-C or
Swift on iOS or in Java for Android.
And something always felt a bit off.
So you could learn any
one of those languages
or pick up the various tool kits
that exist to write native software.
But it's a decent learning curve.
And if you're running a
company or writing an app,
you have to generally pick and choose.
Do I want to target Android?
Do I want to do iOS, or do I essentially
want to do twice as much work?
And so that alone could
be a potential hurdle.
And then there were
these other libraries
that allowed you to approximate the
experience of writing your code once,
and then run it on both platforms.
But there, too, you could always
tell that something wasn't quite
natural for the particular device.
And then more recently
has come onto the scene
a number of new frameworks,
particularly React Native,
an open source framework
popularized by Facebook
that really actually now enables truly
native cross-platform developments
while using JavaScript to
rather stitch things together
and then leaning on the
framework to provide you
with those truly native user interface
widgets and other features that
would come to expect from
those various languages.
So what we'll do over the
course of the semester
is really dive in deeply
to mobile app development,
specifically building on top
of this popular framework.
You might have heard of
Reacht Native or React
in the context of web browsers, which
has been around for some time as well.
And to a lot of those paradigms that
folks have been using for a few years
now on laptops and desktops is now
available with additional features
in a mobile context, especially.
So today we're going to dive in
quite quickly to JavaScript itself.
If you have a bit of background
in that, that's great.
We'll hopefully fill in
some gaps along the way.
And we'll also look at some of the
more advanced features both tonight
and next week as well,
particularly ES6 6 or ECMAScript 6,
which is essentially the
latest version of JavaScript,
and with it some new syntactic
features and programmatic capabilities.
A week after that, we'll
take a look at React itself
and JSX, which rather comingles
code with XML or a markup language,
if you're familiar.
And then look at some of
the particular features
and UI features that you get
with a framework like React JS.
Components, props, how
you deal with states,
how you can actually stylize things,
get user input, and create views,
if you're familiar with paradigms
like MVC, model view controller.
Review governs what it is the user
is seeing and interacting with.
We'll take a look at
debugging techniques,
particularly for a mobile platform,
which might not necessarily be obvious
if the device you're working on is
here, and the device you're testing on
is here.
We'll give you some tools
and techniques for that.
Focusing ultimately on data and
navigation, how you can actually
get users around in your applications.
And then looking at a popular
third party tool and framework
called Expo, which actually
makes it even easier
to develop for this
particular environment
and get started and
get worked on quickly.
Looking at Redux and state
management again more generally.
Performance tuning of your applications.
And then finally how you
actually get this thing off
of your laptop or desktop
and off of just your phone
and on to other phones
and mobile devices.
And we'll apply all of
these lessons learned
and the real challenges, and the
hands dirty portion of the class
will be by way of the course's projects.
Three of them assign specifications from
us that spec out exactly what it is you
should aspire to build.
And then the class will culminate
with the final project, where
it will be up to you to propose, to
design, and ultimately implement most
any mobile application a top
React Native, as you might like.
Without further ado, let's dive
into an overview of the class itself
as well as, then.
JavaScript.
Let me turn things
over already to Jordan.
JORDAN HAYASHI: Great, yeah.
Thanks for the great intro, David.
So a few things about
the course itself, you
can find information on the website.
I e-mailed you all the
link earlier today.
On it, there's a link
to the Slack, which
is what we're going to use for
pretty instant communication.
You can create groups
amongst yourselves,
and we'll use that for any quick
tidbits when we have to send out.
And then, additionally,
we have our staff email
that's linked as well, which is how
you can just email the staff directly.
And so a little bit about lectures.
We'll have a short break about halfway.
You can get up, you can use the
bathroom, go rest your legs.
If you have a question at
all during the lecture,
feel free to just shoot up your
hand or interrupt me directly.
Concepts constantly build on each
other, so it's pretty important
to learn everything
up to a certain point
in order to build off of it later on.
And if something isn't super
important to know when you ask
a question about it, I'll let you know.
So don't worry about
asking dumb questions.
And the staff will be monitoring
the Slack during lecture.
So if people online have any
questions, feel free to post there,
and the staff will interrupt me.
Another thing, I love live examples.
I think the best examples
are created on the spot.
And with that comes
a little bit of risk.
So live coding does have risks.
If I make a mistake,
feel free to correct me.
I have some candy in the lectern.
So if you correct me,
I'll give you some candy.
For those online, sorry you don't get
candy, but you can have some glory.
Cool.
Let's start talking about JavaScript.
So JavaScript is an
interpretive language.
So I posted a little
bit in the Slack earlier
asking about most comfortable languages.
Most of you guys were
saying JavaScript, but I
know those of you who took CS50
might have some experience with CE,
which is a compiled language.
So JavaScript is not compiled.
It's actually interpreted, so an
interpreter will read line by line,
execute that code line by line.
Each browser has built into
it its own JavaScript engine,
which either interprets the code.
It might do some magic with
some just-in-time compilation,
but for the most part it's just
reading your code line by line
and executing it.
Each browser actually has its
own engine, and there are names.
So chrome is called V8.
If you've heard of Node.js at all, it
also uses that same node v8 engine.
Firefox has SpiderMonkey.
Safari has JavaScriptCore.
Chakra for Microsoft Edge
and Internet Explorer.
You don't really need
to know these names,
but it's a little bit important just
to know that different ones exist,
because JavaScript actually
is built off of a standard.
The standard is put out by ECMA,
which stands for the European Computer
Manufacturers Association.
And that association is in charge of
just putting out a spec, meaning hey,
I know you guys have this language.
But this is exactly what
this language needs to do.
And for every single
function, this is exactly how
this function should behave.
So each of these browsers--
the engines in the browsers--
actually implement the standard.
But there are some functions where
the standard is a little bit hazy on,
or maybe it doesn't even define
this particular function.
And there's no hard line in exactly
what that function should do.
So they may differ for anything
not defined by that standard.
And some syntax.
Let's actually hop into
code directly for this.
So let's do-- cool.
And the way that you declare
variables in JavaScript,
there's actually three different ways.
We'll talk about that
a little more later.
But for now, we'll just use
this keyword called const.
So if I want to declare a
variable, I'd say const.
So give me a variable called first name.
And I can give it any value I want.
So let's just call it my first name.
So you notice I have a
string literal there.
It's using double quotes, and then I
end that statement with a semi-colon.
I can also do a last name.
And if you notice, this time, I
still have that string literal,
but this time I'm using single quotes.
Because in JavaScript
there's really no difference
between double and single quotes.
You also notice I omitted that
semi-colon, which in JavaScript is OK.
So my colons are actually optional.
So say I wanted something
that was not a string.
I can just give it a value, like 42.
So in C, you might see
something like, give me an int,
or give me a string or a char star.
You're declaring types
right away with C,
but for something like JavaScript,
you actually don't have to do that.
We can also do arrays.
And we can just declare them in
line like this, and I can have--
So, if you notice, I actually have
three different types all in this array.
So I have a string, I have a
number, and I have a function.
And this is perfectly fine.
JavaScript doesn't really care
what you throw in an array.
You can have all sorts of
different variable types.
And so say we want to access
those things in an array.
Anybody care to guess
exactly how I would do that?
So say I want to execute that function.
How might I go about doing that?
Any guesses?
Yeah.
Yeah, exactly.
The array of two.
So if you're familiar with
other languages, a lot of them
have the same syntax for
indexing into an array.
And so since we have three
things in this array,
we do what's called zero indexing,
whereby the first index in that array
is called the zeroth index.
And then you count from there.
So we have zeroth here,
first, and second here.
And so say I want to
access that function.
I just do array 2, and
I get that function.
And say I now wanted to
execute that function.
I can, say, execute it like that.
So this is something that you
might see in other languages,
but JavaScript you can do it as well.
You can just grab that function out of
that array and execute it like that.
Say I wanted a for loop, and I wanted
to console log everything in that array.
I can do it just almost
like C. So I can do for--
this time we'll use
let for the variable.
We'll talk a little
more about that later.
So I start at zero.
Well i is less than the raised length.
[TYPING]
You might see me--
my personal preference is
to omit the semicolons,
but you might read something
online that has them.
It really doesn't matter all that much.
And so this line of code here.
You might have seen a for loop in
other languages that you've used.
So this one is just saying
for give me a variable that's
called i that starts at zero.
And while it's less than the
number of values in the array--
array.length-- just
keep incrementing it.
And then every single
time console.log, which
is JavaScript's print function,
whatever that value in that array is.
So we can actually run this.
And as you see the first
time, line 12, where
we say index into that array to
the second value, and call it.
That's what's printing high.
And this for loop here will now
print string 42 and this thing called
function, which is this function.
Cool, any questions on syntax?
Yeah.
AUDIENCE: In your array
there, does it matter if you
have that third comma after your--
JORDAN HAYASHI: It does not matter.
So the question was, does it matter on
line 9 that comment at the very end?
And so JavaScript allows you to have
trailing commas, meaning in arrays,
objects, or even function calls.
You can actually have extra commas, and
it doesn't matter whether you have it
or not.
It's optional just
like the semicolon is.
But were I to omit
the comma here and try
to run that, I'm going to get
a syntax error as expected.
Cool, any other questions?
Great.
So back to slides.
So types.
So we talked about types
a little bit earlier,
and I'm just going to talk a
little bit more about them.
So JavaScript has what's called dynamic
typing, meaning given a variable,
it has no type associated with it.
So just like I said, give me
a variable called first name
and set it equal to a string.
I could actually change
that later to, say, a type
number or a Boolean
or anything like that.
And JavaScript is fine with that just
because it has those dynamic types.
And there a certain
number of primitive types.
Primitive types are types that have
no methods, and they're immutable.
And so undefined, null are two of them.
Boolean.
Everybody should know
Boolean true or false.
Number 1, 2, 3, negative 1, 2, 3.
It has no float, so 0 and
0.1 are both of type number.
String, which are the
things between the quotes.
And then symbol, which is
something that's new in ES6,
but we're not going to talk about
it, nor are we going to use it,
and then everything else is an object,
and we'll talk a little bit more
about that later.
Cool and so a lot of languages
have this thing where
you change one type to another type.
So since JavaScript
is dynamically typed,
we have this thing called typecasting.
So coercion is the act of changing
one type to a different type,
and there's two different ways
you can coerce these variables.
So say, as an example, we
have this const called x
and we give it a value 42.
Say I wanted to change
that value to a string.
There are a couple
different ways I can do it.
There's explicit coercion.
There's implicit coercion.
So explicit is, hey, I'm
just going to tell you
exactly what I want by wrapping
it with the type that I want,
and give it to me.
And so that's being very
explicit with what I want.
And so the example of
that would be say I
want to get a string from that value x.
I just wrap it with capital string,
and it pops out 42 with a string.
There's also a way of
doing it implicitly,
which is I'm going to rely
on the behavior of JavaScript
in order to get this to a string.
And so say I want to
add 42 to empty string.
That wouldn't really make sense
if I wanted to have a number,
but since 42 is easily
castable to a string,
I can say, hey, give me
42, add an empty string,
and I expect to get back
something of type string.
That is called implicit coercion.
And so how might we go
about comparing-- oh, yeah.
Question.
AUDIENCE: Is the string passing
behind the same ex.2 string?
JORDAN HAYASHI: Yeah, so another
way would be to invoke that.
So the question was,
what about ex.2 string?
And so yes, another way to
get from a number to a string
would be to invoke that method on
the string or on the number, sorry.
Cool, and so how might we
go about comparing values?
So in most languages you can compare
values with the double equals,
but JavaScript has this
thing called triple equals.
So there are two different
ways of comparing equality.
There's double equals and
there's triple equals,
where double equals will
actually coerce the types,
and triple equals require
that the types match.
And so let's play with
that a little bit.
So say I have this value, and I want
to know exactly what type that is.
So there's this operator called typeof
in JavaScript where I can invoke this.
And that will give me the type
of whatever that variable holds.
So if I were to run this code,
then it would say number,
because that is the type.
So right now in order to
execute my JavaScript,
I'm using this thing called node,
which, as mentioned earlier,
is basically a command line runtime for
JavaScript, which is built off of V8.
Any browser has a console where you
can also just type JavaScript directly
in there.
So if I were to open up the tools on
Chrome, which is my browser of choice,
I actually get this, which
is a JavaScript console built
into all of these browsers.
So if you guys are using Chrome at
home, and you want to follow along,
you're welcome to open up
the developer tools here.
Go to console, and you have your
own JavaScript interpreter here.
So say I wanted to do that thing
where I do const x equals 42,
and I wanted to get the
type of that variable.
I can just do typeof x, and
it will output that number.
So there's a little bit of a caveat with
this, where this might surprise you.
So who thinks they can
guess what this will output?
First of all, what should it output?
So if we remember back a few slides, we
talked about all the different types.
One of them is undefined,
one of them is null.
And say I want to get typeof null.
So what should it output?
Yes?
AUDIENCE: String.
JORDAN HAYASHI: String,
why would you say string?
AUDIENCE: Because [INAUDIBLE].
JORDAN HAYASHI: That's a good guess.
So basically, the answer was so if you
can console log it must be a string.
And while that is correct, most of these
types can actually be cast to string.
So we talked about implicit
versus explicit coercion.
And the way that console
log works is it actually
will turn these values into a
string in order to console.log them,
but it doesn't necessarily mean the
typeof that value itself is a string.
Yeah?
Yeah, so the null.
So we would expect the typeof null
to be null, since null is actually
a primitive type.
However, this actually returns object.
So JavaScript does have
some strange behaviors.
This is one of them.
And people often ask,
hey, we're on ES6 now.
There have been six different
versions of JavaScript.
Why don't you just
change this to be null?
And the answer that ECMA gives is,
well, the whole internet would break.
And so each new version of
ECMAScript should definitely
be backwards compatible
with the previous versions.
Otherwise, say I put
out a website tomorrow.
If somebody comes down and
changes the JavaScript spec,
then my website might break.
And so a lot of websites
actually rely on this to be true.
And, therefore, if a breaking
version of ECMAScript is released,
it might actually just have
unforeseen consequences.
So this is just one of those
strange JavaScript gotchas.
Cool, so another good question would
be so when should I use double equals
versus triple equals?
And people generally say you
should never use double equals,
because that means you have to know
exactly how every single thing coerces.
And not only you, but every
single person who reads your code
should know what all
these values coerce do.
And some of them might
be somewhat surprising.
So we have a chart here that talks
about the JavaScript equality table.
For those of you who have the slides
opened, you can click on that link,
and it will bring you to
the repo that has this.
Basically, some of these
strings are somewhat strange.
Like how empty array is double
equals to false, which doesn't really
make a ton of sense.
A lot of these don't
really make a ton of sense
and, basically, never use
that double equals because it
might have some strange behaviors.
So moving on with coercion.
So we talked about coercing
things into other types,
but how about if we're getting to bools?
So JavaScript has these
things called falsy values.
Who can name a falsy value?
So falsy value is any value that,
if cast to bool, becomes false.
AUDIENCE: Two.
JORDAN HAYASHI: Two?
So two is actually truthy.
So every number except for one number
is truthy, well two numbers actually.
AUDIENCE: Zero.
JORDAN HAYASHI: Zero would
be one of them, yeah.
Not a number which is actually a number,
of type number, is also a falsy value.
Who can name another falsy value?
AUDIENCE: Blank?
JORDAN HAYASHI: Blank what?
AUDIENCE: Or empty.
JORDAN HAYASHI: Empty what?
AUDIENCE: Empty array.
JORDAN HAYASHI: Empty
array is actually truthy.
False is another one.
Undefined, null.
So those are the five falsy values.
So who can name some truthy values?
Somebody said two, which is a valid one.
Three, four, every other number other
than zero, negative zero, not a number.
Empty array is also another truthy.
Empty object and
literally everything else.
So anything other than those
values right there are truthy.
Cool, so objects, arrays,
functions, objects.
It looks like I put objects twice
there, but I actually put it four times.
So JavaScript has this weird
thing where if it's not
one of those primitive
values, it's an object.
And so we'll talk about
this thing in a little bit
called prototype
inheritance, which talks
about how these objects
inherit from each other
and how they actually
work under the hood.
But first let's compare those two types.
So we talked about primitives
earlier, which is--
who can name some of the primitives?
AUDIENCE: Null.
JORDAN HAYASHI: Null, undefined.
AUDIENCE: Number.
JORDAN HAYASHI: Number.
AUDIENCE: Boolean.
JORDAN HAYASHI: Boolean.
AUDIENCE: String.
JORDAN HAYASHI: String.
And simple.
So good, you got them all.
Nice.
So everything other than those
primitive types are actually objects.
So primitives are immutable,
which means if you
want to change them, you're actually
replacing them with a new value
rather than actually changing them
themselves, whereas objects are not.
They're actually mutable.
So who knows what storing
by reference means?
So storing by reference
means we actually
store a reference to this object
thing, and we can actually
change what is held there
without actually changing
where that thing is located in memory.
We'll talk a little bit
more about that in a second.
But the opposite of that
would be storing something
by a value, which is what
happens when you have primitives.
So, like I said earlier,
primitives are immutable,
which means once you create a
primitive, it can't actually be changed.
And when you want to change something,
you actually create a new primitive
and replace the old one, whereas
mutable things are actually
stored by reference, and you
can actually change that object.
And so let's play with
that a little bit.
So there are a few different
ways to create an object.
One would be this way.
So just saying, give me a new object.
And so now o is this a new object thing.
And say we want to start
populating the object.
We can do o.firstname
and assign that a value.
o.lastname, assign
that a different value.
Notice that I have strings with
double quotes and single quotes.
It doesn't matter.
So something other than a string.
We can do a Boolean, so isTeaching.
We can assign that to true.
o.greet, and we can
give that a function.
[TYPING]
So that would be one way
of creating a new object is
to use this new keyword
along with capital objects.
And that says, hey,
give me a new object.
And I'm just going to fill it up with
these values using this dot notation.
Another way to do that would be
what's called an object literal.
So I can just do open
curly, close curly, and that
gives me basically a new object.
This is actually the preferred way
over that old new key word with object,
mostly because a, it's easier
to read, and well mostly just
because it's easier to read.
And so I can start filling those
values in with o.firstname.
And another way to index into
these objects is to do o.lastname.
So notice I use brackets there,
which means inside this bracket,
I'm going to have some
value, and that value
is going to be that key of that object.
So I can do the same thing here.
And say I actually wanted to use not a
string literal inside these brackets.
I could also do that.
So I could do isTeaching and do
o and then pass in this variable
here with a value of isTeaching,
and that will set that key.
And then say I wanted to do o of
greet and give that same function.
Call and so those objects
are basically the same.
And last, we can actually
put everything in line.
So we can do this.
[TYPING]
Cool, and so those three objects
are basically the same thing.
It's just three different
ways of declaring objects.
You can also nest objects.
So say I wanted an
object within an object.
That's also fine.
Say I wanted to do something like this.
[TYPING]
That's also fine.
So that's an object within an object.
Any questions with that?
Cool.
That's actually--
AUDIENCE: I have a question.
JORDAN: Yeah.
AUDIENCE: Do the elements of the objects
all have to be labeled with strings?
Like if a key were numbered,
say, would that work?
JORDAN: Um, So anything, so anything
here, is interpreted as a string.
So say, we were to do, like this,
That would be, basically,
one as a string.
So that, this value here
will be cast as a string.
And that's what will be used as the key.
So the question was, can
we use numbers, or anything
other than strings as keys in objects?
And the answer is, kind of,
because everything will just
be cast to a string.
Yeah, great question.
Let's actually copy and
paste this into our browser.
And we confirm that it works.
And so, how might we go about
getting those values back out?
So, it's basically the
same way we got them in.
So if we do dot, we can see, oh, these
are all, this is the browser saying,
oh, these are all the
keys of the object.
So I can do o3.address, and it
will give me back the object.
And say we want to get
this number out of here.
How might we do that?
[TYPING]
AUDIENCE: Dot and the number.
JORDAN: Exactly, dot number.
Alternatively, we could
have also done this.
[TYPING]
And gotten the same thing.
Any questions with objects?
Yeah.
AUDIENCE: Is there a
conventional way to do that?
Or is it kind of like reference?
JORDAN: To do what?
AUDIENCE: Just between dot
number and [INAUDIBLE]..
JORDAN: Yes, so the question
is, is there a conventional way
to get values out of objects?
Generally the convention is
to use that dot notation.
So say we wanted
o3.address.number, the convention
would be to use the dot
both of these times.
But say we didn't know exactly
what we wanted out of it.
We could, so say we had this--
[TYPING]
Something like that, where
we have some dynamic key.
Where the key we didn't
actually know, that's
when you actually have to
use the bracket notation.
Where we have o3.address, and
then we pass into it that key.
Since key is a dynamic,
since it's a variable,
we don't know what it is, we have to
then use that bracket notation rather
than the dot.
Great question.
Yeah.
AUDIENCE: Um-- You cannot
do 0.1 for example.
[INAUDIBLE]
JORDAN: So, if we did o.1, yeah,
so, o.1, 1 here, since we're
typing it here, is a number.
And we cannot set keys to numbers.
But if it were an object
literal like this,
[TYPING]
JORDAN: It considers this not to
be a number, but rather a string.
AUDIENCE: You can the array assignment
by putting brackets around the one
and passing it as a
string, so you can do 0 dot
[TYPING]
AUDIENCE: Our brackets
around [INAUDIBLE] o
dot open bracket, open
braces, and then, quotes, one.
And then set that to a value.
JORDAN: So, I think you mean this?
[TYPING]
Yep.
And I believe you can also do this.
[TYPING]
Because that will get cast to a number.
I mean a string.
Any other questions?
Cool-- yeah?
AUDIENCE: If you have want the number
one inside the bracket notation,
versus the string one
inside the bracket notation,
it will be treated as the same keys?
JORDAN: Yeah, so the question is, what
is the difference between this here,
and this here?
The difference is, anything
between the brackets
will get coerced into a string.
And so, since this is already a
string, it's just that string one.
Since this is not of
type string, it actually
gets implicitly coerced into a string.
And so, like we saw earlier, if
we did one plus some empty string,
we get back the string one.
So this becomes a string one,
and it will index into that.
Whereas, this number
here, so if we did o3.1,
[TYPING]
That one does not actually get coerced,
like it does between the brackets here.
So JavaScript is basically saying,
hey, this doesn't really make sense.
I need a string here, not a number.
Cool, any other questions?
Great-- So, let's talk a little
bit about this thing, where
I was talking about mutating objects.
So say--
[TYPING]
So, say I had this object, so--
In it we had, a gets a, b gets b.
So say I wanted to change
a to be something else?
How might I do that?
Yes.
AUDIENCE: dot a equals--
JORDAN: Yes, so I can update
this to be anything else.
[TYPING]
Cool, but say I actually did this.
[TYPING]
Anybody care to guess what
would be console logged here?
So basically, what he's doing
is, we're creating a new object.
And storing it in o.
This object has two keys, a and b, where
their values are a and b respectively.
I'm creating this new object
called o2, and assign a value of o.
I then go reset o.
Not o2 but o.a to be a new value.
And I'm going to console log o2.a.
Anybody care to guess what
this is going to console log?
Yeah.
AUDIENCE: a?
JORDAN: So, a guess is a.
What would be the alternative guess?
AUDIENCE: New value.
JORDAN: New value--
[INAUDIBLE]
JORDAN: Yeah, so let's run that.
So you get new value.
And so I talked about this thing
called passing by reference,
and passing by value.
So, basically what's happening
here, is that o is being said,
hey, give me a new object, somewhere.
And then store inside of it, a and b.
And then o2 says hey, give me
another object and set it to o.
And rather then creating a new
object, with the same keys and values,
it's actually pointing
to that same object.
So this is a case where
things are getting stored
by reference, rather than by value.
Meaning, so in CS50, we talked
a little bit about pointers,
and this is the exact same concept.
Where these objects are not stored
as entire serialized objects,
but rather as references
to these objects in memory.
So o and o2 are both referencing
that same exact object.
So when we go back and say,
hey update o.a to be new value,
it's changing this
object here, and still
o and o2 are both pointing
to that same object.
So if I were to have updated 02
here, and console logged o.a,
we would get that same result. Because o
and o2 are still both referring to that
same object in memory, and we're
still updating that object here.
Does that make sense?
Yeah.
AUDIENCE: So what if you
wanted them to be different.
Like, what if you wanted them
to not point to the same thing?
JORDAN: Yeah, so the
question is, what if we
wanted them to have the same
value but be different references?
How might we do that?
There are two different ways.
One, the more annoying way, would just
be to type the whole thing out again.
[TYPING]
So now we're guaranteed
that o and o2 are
going to be different references to
an object that is basically the same.
And another way would be --
there are multiple
different ways to do this.
The most common way in pure
JavaScript, would be to do this--
[TYPING]
Whereby, object assigned is
basically saying, hey, pass in to me
a bunch of arguments.
And every single argument, I'm going
to merge into the previous one,
those lose keys and values.
And so this is saying,
give me a brand new object.
So I'm using the object literal
here to mean a new object.
And then merge into it, of the keys
and values of this object called o.
And so this is basically
saying, give me new object,
and then set all of the keys
and values of o to be in there.
So this is the way of cloning an object.
But say we actually did this
[TYPING]
So, what do we expect
this to now print out?
So, we mentioned that line nine,
we're taking the keys and values of o,
and merging those into a new object.
And then that line 11 we're
taking o2, getting the dot object,
so accessing the value
with the key called object.
And then setting that object's
key called key to new value.
And then now console
logging o to object dot key.
Yeah.
AUDIENCE: So, new value?
JORDAN: Yes, so this, so
the guess is new value,
and that is absolutely correct.
So this, so-- line nine here is
doing what's called a shallow copy.
Which is just grabbing the
keys and values of some object,
and just setting those blindly
into some other object.
As opposed to what would
be called a deep copy.
Where that would take
the keys and values.
And then if the values
are objects, you'd
also take those objects keys and values.
Do that recursively, and basically
get every single layer deep cloned.
But since object assigned just
takes the keys and values dumbly,
if we have an object in there,
update that object's key.
o.obj and o2.obj are still referencing
that same object in memory,
so since we updated--
we mutated that object, it
would update in both o2 and o.
Does that makes sense?
Great, any questions about this?
Yeah.
AUDIENCE: How would you do a deep copy?
JORDAN: So, how would you do deep copy?
That's a great question.
There are multiple different ways.
So most people would say use a library.
Meaning, rather than implementing
this thing on your own,
just take somebody
else's implementation.
But lets, let's actually do that.
That's a good question.
So, how would we do a deep copy?
[TYPING]
So, I know we haven't talked
a ton about JavaScript yet,
but lets actually tried
to do this together.
So, let's call a function, deep copy.
And we're going to pass
into it some object.
And how would we implement
this, if we're guaranteed
that no objects have values of objects?
Meaning we are guaranteed not
to have objects within objects.
How might we do this?
AUDIENCE: Check for the type of the key.
JORDAN: Yes, so we can check
for the type of every key.
But if we're guaranteed that no
values are going to be objects,
we can just do a shallow copy right?
Yeah.
AUDIENCE: So check every value?
And if it's, the value is [INAUDIBLE]
we have to recursively deep copy that.
JORDAN: Yeah.
So hold that thought.
Let's actually implement
this as if we know that there
are no objects inside of objects.
So if that were true, we could
just return the shallow copy right?
So object.assign
[TYPING]
So this would be a perfectly
valid implementation,
if we knew that there's no such
thing as objects within objects.
But since there are, we're going
to have to do some magic here.
So, can you repeat your
recommendation again?
AUDIENCE: So, check if the--
any of the values is an object.
Then you can't just take
that value into a new object,
just to reference the same object,
we need to deep copy that object,
instead of just taking [INAUDIBLE].
JORDAN: So basically, so
check every single value,
and see if it's an object.
If it is an object, then go
ahead and deep copy that object.
Otherwise, return that value.
Cool.
So let's do that.
So-- the way to get the keys of
an object, is this function called
object.keys
[TYPING]
So, so by doing object.keys
and passing in the object,
we now have an array full of the string
values of the keys in that object.
And so what we're going to do is, we're
going to iterate through those keys.
Check to see if the
value is of an object.
If so, we'll go ahead and clone that.
Let's not worry about functions, or
any of those other things for now.
Otherwise, just return that value.
So, let's have this for loop--
[TYPING]
And do that.
So first, let's define--
[TYPING]
The new objects that
we're going to return.
And let's just start with
an empty object for now.
And so, now we have to check to see
if each of these values is an object.
If so, copy it, otherwise return.
So how are we going to check
the type of a particular key?
AUDIENCE: Type of operator.
JORDAN: Yeah, exactly,
that type of operator.
So we can do if the type of
obj, and then pass in by keys.
[TYPING]
So what do we want to check against?
[TYPING]
All right, what am I doing wrong here?
AUDIENCE: Three equals.
JORDAN: Yeah, we should always
use that three equal signs.
In this case it would matter.
But, we should just get in
the habit of doing that.
I mean so if you notice here, we
actually have bracket notation
within bracket notation.
That is totally fine.
Cool.
So, if something is an object
to what are we going to turn?
We can do object, new
object with that key.
[TYPING]
Equals-- what?
AUDIENCE: The value?
Oh no, I'm sorry, deep copy.
JORDAN: Yeah, let's actually
deep copy that value to two.
[TYPING]
Otherwise--
[TYPING]
We can just set it
equal to the other key.
[TYPING]
And then at the very end, we
can just return that new object.
[TYPING]
Cool.
Anybody see any bugs?
Candy opportunity.
All right, let's just
go ahead and test this.
So-- let's do--
Do copy o--
Then update o--
[TYPING]
o.obj.key Let's say of to new key.
[TYPING]
o3.obj.key.
Get rid of that.
All right, so moment of truth--
[TYPING]
Key, rather than new key.
So we did it.
Whew.
All right, any other questions about--
objects, mutating,
references, any of that stuff?
No, great.
So, arrays as well, are
also stored by reference.
So if we were to do
the same exact example,
and rather than updating the
object, we updated that array,
we'd end up with the same exact results.
And so, if we were to update our
deep copy function to also take
care of arrays, all we have to
do is also check, rather than
checking object, also check against
arrays or any other data types
that we're going to check.
Let's move on to prototype inheritance.
So what exactly is
prototype inheritance?
Well, so non-primitive types
have a few properties and methods
associated with them.
So, array, we have this
thing called array.push,
which will add values to an array.
So, say we have something like--
[TYPING]
An empty array, if we did array.push--
some value, then array
now has something in it.
If we were to push
another value into it--
It now has two values in it.
So array.prototype.push
is a method that we
have available on all arrays, that
just adds new values to an array.
Another one would be like,
string.prototype.toUpperCase.
So, say we were to
have some string, so--
[TYPING]
If you do str.toUpperCase--
Now we, we're left with a new
string with all uppercase.
So, these are just functions that we
can invoke on any non-primitive that
gives us something else.
That is available to all
non-primitives of a given type.
So each object stores a
reference to its prototype.
Meaning, it has all the-- it
knows about all of these methods.
And it stores a reference to the object
in order to know where these methods--
the code to actually the run that lies.
And say we have a
prototype chain where there
are a bunch of different
methods of the same name.
Whichever one is bound most tightly
to the instance has the priority.
So say we have an object in
an array, where array is the--
So say we have a value that is of
type array, up the prototype chain
we have arrays, its prototype is
array, that prototype is object.
Say we have the same named
method on both of these.
If we call that method, the one
that's bound most tightly the,
array will take priority.
So let's actually show that.
So, say we have something like--
So array, it has a
reference to its prototypes.
So if you did array dot, double
underscore, proto, double underscore,
we see this large object with
a bunch of different functions.
And so we see down here, push, which
is that one that we invoked earlier.
So this is exactly how it knows
where that push implementation is.
And so we can do
arr.__proto__.__proto__,
and go even farther up the chain.
So this one has a bunch of other
ones toString value of, whatever.
And if you notice, both the arrays
prototype, and it's arrays prototypes
prototype, have this
method called toString.
And if I were to invoke
arr.toString which one of these
is going to actually get called?
AUDIENCE: The second one.
JORDAN: The second one?
Which one is the second one?
AUDIENCE: Dot proto, dot proto.
[INAUDIBLE]
JORDAN: Dot proto, dot proto.
So, actually the opposite.
So, since the toString,
on the array prototype,
is more specific than the toSting
method on the object prototype,
this one is going to get invoked.
Because its, just because
its more specific.
Because an array is an
array and its an object.
But its more specific to call it an
array, than to call it an object.
So its going to invoke
the one on the array.
Does that makes sense?
Anybody have a question about that?
It's an important concept, and
a little bit confusing at first.
Cool.
Most primitive types
had object wrappers.
And so we talked about
how primitive types don't
have any methods associated with them.
But primitive types
also have wrappers that
have prototypes associated with them.
What the heck does that mean?
So if I were to do
42.toString, It's going
to be like what the heck do you mean?
42.toString--
[TYPING]
Right I told you that these
primitive values don't have methods.
And so 42.toString
doesn't really make sense.
But say I were to do this thing
const num = 42 and did num.toString,
[TYPING]
That will actually do something.
And that's a little bit strange.
This is another one of those
JavaScript interesting behaviors.
Because all of the primitive
values have wrappers
that give them access
to a bunch of methods.
And JavaScript will automatically
do what's called boxing for you.
Which it says, hey, like
I know 42 is a primitive,
but if you call this toString
method, I know what you mean.
I'm going to box this 42
number with this prototype that
has a bunch of these methods on it.
So if I were to do 42.toString
that would make sense.
And if I num.__proto__,
[TYPING]
That actually exists.
But 42.__proto__
[TYPING]
Does not.
Does that make sense?
Another way to find out if a
value is an instance of some type,
you can do this thing
called x instance of number.
And that would return false.
Because x is actually not
of type capital number,
it's just boxed around that
number object for your reference.
Does that make sense?
Again not something you're going to
use everyday, just something that
is helpful to know in case you
run into the strange corner cases.
Cool.
So why would we use a
reference to the prototype?
And what is the alternative there?
Anybody care to give a shot at that?
So this is going back a little bit too
deep copying versus shallow copying.
AUDIENCE: So, maybe if the
initial object is massive.
And then you just want to do
something, like, after it?
JORDAN: Yeah, so if the initial object
is massive, like, what happens then?
So the alternative is basically
to clone every single--
to deep copy every single
prototype every single time
you couldn't new value.
Which is, safe, because that
number and all of its methods
are all encapsulated within
that specific variable.
But it's also a little bit
expensive in both performance,
because you have to do that
deep copy every single time.
And also of memory, because the
object starts to get pretty large.
And if you have an array of
like 100 different things,
all hundreds of those, deep copying
every single prototype gets pretty big.
And so what is the danger of storing
a reference to the prototype,
rather than copying the whole thing?
AUDIENCE: I guess if
change it, [INAUDIBLE]..
JORDAN: Yeah exactly.
If you change it, then it changes
for every single value of that type.
So let's do that really quick.
So, so say we have, so we solved
num, which is equal to 42, right?
And if you do num.toString,
what so we expect to come out?
42 is a string right?
But say, some devious
programmer was doing this thing
where he did number.prototype.toString
[TYPING]
And you actually override that to be
some function that will return 100.
Now what happens if I
call a num.toString?
Wait a second.
[TYPING]
So that could have some
dangerous penalties right?
So if I were to change the
prototype of the number class,
even though num was declared 100
lines prior to be the number 42.
And we tried num.toString
here and it returned 42.
If we were to change
the prototype later,
it affects everything
that has ever happened.
So num.toString now
starts returning 100.
And everything that will happen.
So if I were to do--
[TYPING]
Everything in the future
also has those consequences.
So changing the prototype is
something that is very dangerous,
and is recommended against doing.
Does that make sense?
Cool.
So let's actually take a short break.
All right welcome back.
So let's talk about scope now.
So what the heck is scope?
So Scope is a term that's
talking about variable lifetime,
and how long these
variables actually exist.
And so there are a couple
different types of scoping.
There's lexical scoping, which is
that keyword var that you might
see if you're reading old JavaScript.
And there's block scoping, which
refers to how things like const or let
are scoped.
So lexical scoping is basically
saying, hey, give me a variable
and it will exist for
as long as since it
was declared all the way until the
end of a function ends or the file
if it's in a file.
Whereas the analog
would be block scoping
where it behaves a lot like
something behaves in C.
Where basically a
variable will be around
from when it's declared until the
next end curly brace is reached.
And so that there is the big difference
between var and const and let.
And the difference
between const and let is
that const is something
that can't be updated,
meaning if I set a variable
to be a constant, it
means I'm not going to
update that reference later,
whereas let can be updated.
So if I were to do const thisIsAConst
and set about equal to something
like 50, if I were to say thisIsAConst
and try to update that to be 51,
I'm going to get an error actually
that says, hey, you call that a const?
But you're trying to change it.
That's not OK.
And so no matter how
I want to change it--
say I do that plus-plus or
something, that's also going to fail.
Whereas if I did something like
let thisIsALet equal to 50,
I can go ahead-- or 51, I made
a typo, but I can just say,
hey, it was a typo, thisIsALet, let me
change that to 50 and we're all good.
I mean, I can also do that plus-plus
or change it however I want
and it will actually update that.
Note that I said the
reference can't be updated.
I did not say anything about
things being immutable.
So if I get const obj equals
this empty object, if I then--
I can't update it to be--
point to a different object.
If I try to do obj is something
else, I'm going to say,
hey, you call this a const and
you're trying to change it.
But I can still do obj.a and set
that equal to a, because why?
Anybody care to tell me why?
Exactly.
So the pointer is still
pointing to the same object.
The reference has not changed.
So we mutated that
object, but it's still
pointing to that same place in memory.
It's still pointing to the
object that exists over here
and that reference has not been changed.
Does that distinction
make sense to people?
It's a pretty important one.
Cool So let's play a little bit
with these variable lifetimes.
So I said before that if I tried to do
something like this, what happens here?
Error.
Why?
Because it's a constant and
we can't update a constant.
And we can confirm this.
Oh.
It'll actually tell
us, hey, a TypeError.
You call this a constant variable
but you're trying assign it.
That's not OK.
But if we did--
this is OK because the reference
to that object did not change,
it's just mutated it.
On the other side, if we did something
like let thisIsALet A Let equal to 51,
and then want to change that
later, we go 50, that's totally OK.
But if I actually tried to
reassign-- so let thisIsALet.
If I tried to do this again, it's going
to yell at me because it's saying, hey,
you already declared
something called thisIsALet.
You cannot declare that again.
And so const and let
actually protect you
from declaring something with the same
variable name twice, which is something
that var does not do.
Cool.
What do you guys think would
happen if I tried to do this?
Anybody care to guess?
Undefined?
So let's try to run it.
Error.
So since these things
are block scoped, it
means the variable is declared
at the line that it is written.
And if we try to use it before then,
it actually does not even exist at all.
So if I tried to console.log something
called thisIsAConst here, remember,
the JavaScript interpreter
is just reading down
and it won't see like, hey,
what the heck is thisIsAConst?
I have no idea what that is so
I'm just going to Error here.
Same thing if I tried to
do this as a let here.
That will also Error
with the same error.
AUDIENCE: So what's line 14 error on?
JORDAN: Why does it error?
Because we're trying to declare two
variables with the same variable
name twice.
So we have let thisIsALet equal
51 here, and we try to do it again
and it's saying, hey, you already
have a variable called thisIsALet,
so I'm not going to allow
you to do that again.
So it's going to be
this error right here.
AUDIENCE: So it's the
instantiation of it?
JORDAN: Yeah.
It's saying like-- basically I'm
saying, hey, give me a variable to call,
this is a let here, and then a
couple lines later I'm saying,
hey, give me a variable
called thisIsALet,
and JavaScript says,
hey, like, you already
have a block scope
variable called thisIsALet,
so I can't give you another one.
However, if I tried to just update
it like this, that's totally OK.
Any other questions here?
So the other thing we said, we can
have these things called a var.
If I did var thisIsAVar equal to
50, that's fine, I can update it.
That's also fine.
I can also do this, and
that won't yell at me.
So vars are older ways
to declare variables
and they don't have the same
protection that let and const do.
You can override them like
this and it's totally OK.
And you can actually declare a whole
new variable with the same variable name
and that's also OK.
And something-- yeah?
It just-- yeah, so that's--
So if I try to run this,
it will update the old one.
It'll just replace that value.
It's actually called shadowing,
where you create a new variable
with the same variable name
which basically just overshadows
that old one.
So it's as if the
other one didn't exist.
Cool, so check this out.
So this errors and we know this errors.
But say I were to do this.
You'd expect this to also
error, but actually it does not.
It returns undefined.
So this is another weird
thing about JavaScript.
This is called hoisting.
And so certain things
are hoisted, which it
means basically it takes
the definition of something
and hoists it to the very top
of the file and does that first.
Get
And a few things are hoisted.
Var the-- actually, the declaration
of the creation of an empty variable
are hoisted.
Function definitions are hoisted
as well, but const and let
are not, as we saw if we tried to access
the variable name of the const or let,
then it errors.
But with a var, the declaration of
that variable is actually hoisted.
And we can talk a little bit more
about how that works in a second,
but let's actually play
with it a little bit more.
So function definitions are hoisted.
So let's clean up this
file a little bit.
So let's call this
new function, called--
so this is console.log.
So I defined this function
called thisIsHoisted
at the very bottom of the file.
And all it does is it
console.logs, there's
a function declared at
the bottom of the file.
But something very interesting is at the
very top of this file, I can call it.
And that will actually work.
And so that is what's
called function hoisting.
The behavior whereby
a function definition
declared at the very bottom of a
file is actually available for use
at the very top of the file as well.
But this does not work in other cases.
So say I were to do something like this.
So who can tell me what the difference
is between line 21 and line 25?
They look pretty similar, right?
Yeah?
OK.
Yep.
So repeating for the camera, line 25,
thisIsHoisted is declared as a constant
so it cannot be changed, whereas line 21
is declared as a function and so it can
be changed, which is absolutely correct.
What happens if I try
to do this up here?
Yeah, so we're going to get an error.
thisIsHoisted is not defined, but why?
Because as we talked about
earlier, these things
called consts are not available for
use until they're actually declared.
So certain things are hoisted.
Var.
So the declaration of these
variables are hoisted.
Function definitions if they're
declared like this are hoisted.
But if we create what's
called an anonymous function,
a function without any name,
and set that equal to--
or assign that to be a constant,
then that constant is not created.
Does that make sense?
So what happens if I try to do this?
Yeah, so same thing.
It errors.
What happens if I try to do this?
What's hoisted?
So notice-- so notice the
difference in the two errors.
They're actually not
the exact same error.
So who wants to give a guess
at what's going on here?
So when I declared it with a let
that's saying reference error,
thisIsHoisted is not defined,
whereas when I use a var,
it says TypeError,
thisIsHoisted is not a function.
Why might that be?
Yeah?
Uh huh.
Exactly.
So repeating for the camera., and
I'll bring up the code as well.
So down here, so the first time
when we declared this with the let,
it's not declared at all.
This variable does not exist at all.
So this is not hoisted,
the JavaScript does not
know what that means on line 1.
But when I use a var
here, remember, it hoists
the declaration of this variable.
So it creates a variable
called thisIsHoisted.
However, it does not assign it a
value until line 25 is executed.
And so at line 1, thisIsHoisted exists.
It's just equal to undefined.
And if I try to invoke
it like a function,
it says, hey, this is
an undefined variable,
I can't invoke it like a
function, this is a TypeError.
And so even though both of these things
errored, the reason that they errored
is slightly different.
In case one when they're
declared using a const or a let,
that variable just
does not exist at all.
However, when we declared
using var, the variable exists.
It's just undefined, and so if we
try to invoke it like a function,
and it says, hey, like, this is
undefined, it's not a function.
Does that make sense to everyone?
So why does this happen?
How does this happen?
And the reason is actually
how JavaScript is executed.
So there's two phases in the
execution of a JavaScript file.
So before executing any code, it
has all of the text in front of it,
but it hasn't executed anything,
it just reads the entire file.
And what's it looking for?
Well one, it's looking for
anything wrong with the file.
So say like my very first example
when I had an array and it was missing
a comma, that's something that's
caught in the first reading.
It says, hey, like, this looks like
an array but it's not quite right.
Like, I see this thing that I'm not
expecting, I'm respecting a comma here.
So that's one thing that's caught.
Other things, maybe it will
add some semi-colons for you
and stuff like that.
And then any function definitions
just get saved in memory.
It says, hey, this is a function,
let's put this in memory
so if somebody wants to use
it at line 1 they're able to.
Variable initializations, if
they're lexically scope-- or I mean,
if they're lexically-scoped
they will be declared,
but they will not be initialized.
Meaning anything
declared with var will be
declared-- like there's
a variable that exists,
but it's not going to be set
equal to anything until later.
And then there's a second phase called
the execution phase, whereby the code
is actually run, it's executed.
And so that is when things
like const or let get invoked--
or get both declared and initialized.
Does that make sense to everyone?
Anybody have any questions on scope?
So why might we take
advantage of this scoping?
Does it seem like a feature
or does it seem like a bug?
Anybody care to guess?
There's no correct answer to this.
It's completely opinion.
Yeah?
AUDIENCE: So you've got a controller
with math functions in it.
JORDAN: Uh huh.
AUDIENCE: You can call the
ones there and lay down
a file so that you can write all
your code in one giant function?
JORDAN: Yes So, one
thing might be we can
have these function
declarations at the very bottom
and then we can use it at the top.
And so that might be good
for code organization.
Like somebody reading
your code would know, hey,
if I'm looking for
these functions, they're
all going to be declared
together at the bottom.
And they might be used everywhere,
but all the function declarations
are all going to be here.
So that might be a feature because
it's good for organization.
So say we're to play devil's advocate.
Who might see this as a bug?
Uh huh.
OK.
So the question is, like, why
can we declare two variables
with the same name when they look
like they're in the same scope,
specifically with this var keyword?
Which is another thing where it's a
bug/feature that a lot of people use.
And so if JavaScript were to be updated
and that bug/feature were to disappear,
a lot of code would break.
So a lot of people have
took advantage of this.
And basically it's the same thing as
like, why is typeof a null object?
Just because it is.
And we can't change that because
people rely on that behavior.
I know it's kind of an anti-answer,
but does that kind of makes sense?
Yeah, you should-- so there's not
really a good reason to use var anymore.
With ES6, everything
supports const and let.
And so I've been using them in all
of the examples except for these.
And I think you should
definitely use them as well.
The reason I'm getting var
is one, so if you see this,
you know what's kind of going on, and
because a lot of legacy code-- a lot
of code written two, five
years ago, 10 years ago
uses var just because
it was the only option.
One thing that I didn't mention
earlier is that you can also
declare a variable like this.
So this is another way
of declaring a variable.
This creates a global variable.
It's something that you probably
won't see that often, there's
really no reason to do it.
But in case you ever see
that, that's what it is.
So if you declare a variable without
giving it a keyword like let, const,
or var, it creates it globally.
But there's no reason for
you to use this, really.
It's just if you ever see
it, that's what it is.
Any questions at all about scoping?
It's a pretty important concept.
And for online folks as well,
remember, you can post in Slack
and the staff will either field
those questions or pass them to me.
Cool So let's move on to
our final topic of the day.
So the global object.
So the way these things all work
is basically in any given runtime,
there's this thing
called a global object.
And so all variables, all
functions are actually
keys or parameters or
methods on the global object.
So in browser, there's
this thing called a window
which is a global object of a window.
So this is a browser environment.
And if I type window, I see this thing.
And it has a lot in it.
But basically the window
is this global object,
and on it there is all sorts of stuff.
So we see $0, $0a.
So these-- so any variable that
you declare in this console
gets put onto this global
object called window.
And so actually, let me open
a brand new browser tab.
And we'll get a little
bit of a cleaner window.
So the reason that we saw these
things called $0, $whatever,
is because I open these dev tools on
the same tab as my lecture slides.
And the way that Google
Slides works is since it's
something dynamic on the web,
it has to be using JavaScript.
And since it's using
JavaScript, obviously it's
creating a bunch of functions,
it's creating a bunch of variables.
And all of these things end
up on the window object.
And so when we check out--
when we inspected the window
object of that particular tab,
there was a bunch of stuff
on it because that's how
Google Slides is working.
And when we created a new
tab, this is a brand new tab
and therefore no JavaScript
has been executed,
so there's a lot fewer variables
and stuff on this new tab.
And so whenever we
create new variables-- so
say we do const x equals this is
a new variable, we see x is this.
We can also do this window.x--
I declare it as a const.
So the way that browser windows
handle these blocks of variables
is a little bit different.
So we'll use var for
the sake of explanation.
So when I create this new
variable called var y,
it is the exact same thing as window.y
And so if we inspect the window,
we see a bunch of things that are part
of the JavaScript API, the browser
API, all of these things.
And if we go all the
way to the very bottom,
so this is stuff that is
created in the new tab.
L, M, N, O, P, Q, R,
S. We see this y here.
So part of that window object
is that variable called y
that we stuck on the window.
And so even though we declared
it with var y equals something,
it ended up on that
global object, and that's
how JavaScript keeps track of
all of your valuables and stuff.
And so what happens when we're in the
node environment and we type window?
up window's not defined.
And it's because in
the node environment,
the global variable is not called
window, it's actually called global.
And if we type global, we
now see all of these things.
And a lot of this will overlap with
that window object in the browser,
but since the browser API has
things in it that is not necessarily
used in the command line
stuff like, give me a DOM node
or give me CSS on this DOM node,
stuff like that, that doesn't really
make sense in a command line
interface, therefore those things
are not on this global object.
And then if we try to type
global, here in the window,
that doesn't really make sense either.
There's another thing that's
just kind of important to know
but you might not ever
take advantage of it.
But does that-- does that make sense?
Cool.
So let's move onto something that we'll
discuss a lot more in the next lecture
but I'll go ahead and introduce
the concept in this lecture
and leave you with a
little bit of a teaser.
So who here has heard
of a closure before?
So closures are actually
one of the things
that JavaScript
programmers hate the most
because it's a very, very
difficult concept to learn.
Mostly because it's always
taught somewhat poorly.
And so next time I'm going to try
to do a good job of teaching you,
but I'm going to show you right now
the problem that a lot of people face.
And so what closures are are functions--
is a behavior whereby functions
that refer to variables
declared by a parent
function still exist,
and it's possibly because of scoping.
What the heck does that mean?
I'll explain it in the next
lecture, but let's go ahead
and explore what this actually means.
All right.
So let's do this.
So first thing I'm
going to do is I'm going
to declare an empty array
called array, and I'm
going to fill that with a few values.
That's And I'm using var intentionally.
And that's push on a
function that does this.
All right So what the
heck did I do here?
So I declared a function
called makeFunctionArray,
and all it does is it creates an
array, fill it with functions,
and then invoke one of them.
And so if I were to call this--
if I were to call this, I'd get back
an array full of functions, right?
And what do we expect those
functions to do? each of them?
Print a number, right?
And so what should
happen is I should just--
I should be able to march through this
array, invoke each of those functions,
and get back something
that counts, right?
Basically?
So let's see what happens.
So I'm just going to access
that first one and invoke it,
and we expect it to print out 0.
So that there is one, a JavaScript
programmer's worst enemy,
because it's somewhat unexpected,
and as we'll see in coming lectures,
that is actually as expected.
So I'll leave you guys on that
cliffhanger for next time,
and we'll go ahead and
officially end lecture.
I'll stick around if you any questions.
