Jonas: So in the last lecture,
we implemented a brand new class
which showed us the need for encapsulation,
so for data privacy.
And so let's now tackle this very important principle
of object oriented programming.
Now, first off, remember that encapsulation basically means
to keep some properties and methods private inside the class
so that they're not accessible from outside the class.
And then we simply expose some of the methods
as a public interface, which we then call an API.
And so those are the methods
that we will allow other developers to use,
so from outside of the class.
And we also call this whole idea data privacy,
and it's really essential to do this
in anything more than a toy application.
Now, as we learned earlier, there are two big reasons
why we need encapsulation and data privacy.
First, it's to prevent code from outside a certain class
to accidentally manipulate our data
that lives inside the class.
And this can happen, for example,
when someone interacts with an object's properties
that no one is supposed to read or to set manually.
And the second reason why we need data privacy
is that when we expose only a small interface,
so that small API that I just mentioned,
just consisting of a few public methods,
then we can change all the other internal methods
inside the class with a lot more confidence.
Because we can then be sure that external code
does not rely on these methods,
and so code will not break
when we do these internal changes.
So that's a bit of a recap of why we need data privacy.
But now about the implementation,
the way that encapsulation
is actually implemented in JavaScript classes
is by using something that we call private fields
and private methods.
And these are part of a big feature called class fields,
which was only introduced to JavaScript classes in ES2022.
So a few years after classes
were initially introduced in ES6,
which is now actually over 10 years ago.
But anyway, before we now go use these class fields,
let's talk a bit about this new feature.
So for starters, why is this even called class fields
and not something else?
Well, in more traditional
object oriented programming languages,
which are usually based on real classes,
what we call properties in JavaScript
are usually called fields.
So again, in these other more OOP languages,
these properties are called fields.
And actually that's where some of the problems
with this new class fields feature actually start.
Because with class fields,
we are now moving away from this idea
that classes are just synthetic sugar
over construction functions.
So with this new class features like these class fields,
classes now start to have abilities
that we didn't have previously.
So originally, there was no easy way
of hiding properties or methods
from the outside of a class or of a constructor functions.
But again, with private class fields,
we'll actually be able to do that.
And so this is forcing the class pattern
even more into JavaScript,
which again is not a class based language.
It is a prototype based language,
but now it's looking more and more
like a class based language like Java or C++.
Well, at least when it comes to object oriented programming.
And many developers consider this to be a big problem.
So there was actually a lot of noise
around this feature when it first came out.
Now, personally, in my own opinion,
I'm not sure if this is actually such a big deal
for the average JavaScript developer.
So as long as you still understand how prototype inheritance
and function constructors work,
I believe that you'll be just fine.
But now enough talking, let's actually get to work
and learn about these class fields.
So as a part of these feature,
let me now actually write what exactly we have.
So first we have public fields.
So this will be nice for you to keep here
so that you know exactly what we're gonna learn
and also what is part of these fields feature.
So, again, public fields.
Then we have private fields.
So these will allow us to implement encapsulation.
Then we have public methods,
which are basically just the methods
that we've been using all along,
like the deposit or withdraw methods.
So those are simply public methods.
And then finally, we also have private methods.
And then at the end, so besides these four,
there's also a static version of these four,
static version of these four,
which we're not gonna talk about here
because they are a lot less important.
So we're just gonna basically create four examples
of these four right here,
and let's simply start with the public fields.
So first of all, what actually is a field?
Well, we can think of a field as a property
that will be on all the class instances.
And so that's why we also call this a public instance field.
This means that we can declare everything as a field
that want to be present on all the instances,
but not on the prototype.
And this is important to understand.
So again, these fields will not get inherited,
so unlike methods that will be added to the prototype
for instances to inherit them.
So basically these fields are just like adding properties
to the constructor like we are doing here.
But now we can do this, instead of in the constructor,
we can declare some of these here as these public fields
or also as private fields.
But for now, let's start with public fields.
So for example, here, this locale here
should probably be present on all the class instances,
because it doesn't even depend on the input, right?
So when we create a new instance,
we pass in the owner, currency and pin.
So remember that from the last lecture.
So, yeah, exactly as we're doing here.
So basically what I did here, by the way,
was just to copy and paste this exact class
that we created in the last lecture.
But, again, what we pass in are these three data points
and so the instance will of course then depend on these,
but all of them will get this exact same locale, right?
And so this is a great candidate for becoming a field.
So let's declare a field and we just do that here outside.
So basically where we also place everything else
like the methods, the constructor and so on.
Let's do this here actually
before the constructor functions.
And so this is now very easy.
We just type locale, then equal and navigator-locale
just like before.
And that's actually it.
Now here, we do need to specify semicolons,
which is a bit weird because we don't need those
after the methods here and after this function.
But here, we do need them.
All right, so we can just get rid of this.
Maybe let's comment it out just to see the difference.
So here, we need no disc keyword,
and also we don't use any const
or let or anything like this.
So just the name of the field and then the value.
And so if we now,
let's just log this account to the console,
then just like before,
we will see that the locale is actually here.
Well, for some reason it is undefined.
And, yeah, actually here it is
language, not locale.
So now we get that locale.
And if we were to create another account object,
then this would get the exact same value.
So again, this is now here on every single instance,
but if we look at the prototype chain,
then of course it is not there.
So this here only the five methods that we have here
or the four methods plus the constructor.
All right, let's say we want another one.
Let's say the name of the bank maybe.
So this can also be on all of them.
And so here, let's do again Bankist
like we had in some other previous project.
And there we go.
So writing it like this
would have been exactly the same as doing this.bank
and then equals Bankist here.
So the exact same thing,
but having these fields here,
which are the same on every single instance,
which makes the class a little bit more self-documenting,
which is one of the good reasons for using this.
So let's get rid of them here.
And so yeah, these are the public fields.
And so now let's move on to private fields.
So private fields, the idea behind them
is exactly the same as with these public fields,
but with the difference that they cannot be accessed
from the outside.
And so one great candidate for this is these movements.
So it makes a lot of sense
to protect this mission critical data
from any interference from the outside.
And so then no one can accidentally
or even on purpose manipulate this data here.
So right now, let's just see an example of that.
So let's say that we do everything normal.
For example, we just deposit some value here,
then we withdraw something,
let's say 100.
And so, yeah, of course, these movements then show up here.
But what if then, for some reason,
we would do acc1.movements
and set them back to an empty ray,
essentially erasing the entire history?
So that would indeed work.
So there we go, but this is very, very bad.
So we do not want to allow this kind of interference
with the data from the outside,
or movements should only be accessed
or should only be read and manipulated by deposit, withdraw,
and maybe some other method that we can create
so that someone can check out the movements.
So instead of having to do something like this.
So, again, we do not want anyone to allow to do this,
so manipulating this data from the outside
without using our public API.
And so what we want to do is to protect this field.
Once again, this actually doesn't even depend
on the input here.
So we can just declare it here,
just like all the other fields with the difference
that we start with this hash symbol here.
So # and then just the name of the field,
which is just an empty array.
And then we can remove it from here.
And there we go.
With this, we just protected the movements array.
Now we will get some errors here
because this field is now actually really called #movement.
And so here we now need to change this name.
So #movements,
and it is actually called movements, not just movement.
And I think that's actually it.
Let's save it.
And, yeah.
So again, you see that now it is called movements here
like this or actually like this.
So that's the hash and that's the array of course
with the two values that we specified here.
But then what happened here?
So this was earlier the line of code
which reset or deposits and withdrawals.
But now what this will do
is to just create a brand new property
and set that to an empty array.
So that's this one right here.
But that's not a problem
because the code inside our class is no longer using this.
So we could also just specify
really something here like this.
And so then after this line of code here runs,
the object would then look like this.
So it would then have this weird array with this weird name.
All right, now here, when we try to access this movement,
it no longer exists.
But what happens when we try to actually access
our private movements that we just created?
So indeed we get private field must be declared
in an enclosing class.
Or in other words, we can only use this #movements
inside of the class.
So let's remove this here and nice.
Now we can actually, as you just saw,
still see this property here in the account,
but that's not what private means.
So private simply means that the data cannot be accessed.
So it cannot be read or be mutated
from anywhere outside of the class.
So that is exactly the goal of this.
Great.
Now let's do another one
and let's now also make the pin here private.
Now this one is a little bit different
because it does actually depend on the input data,
which we can only read here in the constructor,
but not here.
But it is here where we have to specify the private field.
So what do we do?
Well, just like with regular variables,
we can just define the variable here first.
So just like a let variable.
So we just define the private field here
without giving it any value,
and then we assign the value to it right here.
We just need to make sure that we change the new name.
And so then this is all we need to do.
Now without this line of code here,
so if we just comment this out,
then notice how this private pin here
would just be undefined.
So just like a let variable without any value, all right,
but then we do this and so then it becomes 1111,
which is the value that we pass in here.
And we don't even use this pin anywhere here in the cods,
and so we don't need to change anything else.
So this was just an example here anyway.
Now if we think about this, actually in this example,
we could convert everything here to private fields,
but let's keep it simple and just do these ones here.
So I only did this one to demonstrate
how we can first declare basically this field out here
and then define its value inside the constructor,
which is where we have access
to that input value of the pin now, right?
So we already worked on these two.
Let's now move on to public methods.
So these public methods are exactly the methods
that we have worked up until this point.
So all of these methods that we have right here
are right now public,
and so they're part of the public interface,
which we also call or API.
Not like this. (laughs)
Yeah, API.
So nothing new to do here.
Let's just, as I mentioned earlier,
create this new method called get movements
so that we actually give users of this class.
So some other developer that wants to use this class
in the rest of the code a way to read the movements.
All right, so that's exactly what the API is for.
So giving other developers ways to interact with our data.
So here we just return this.movements and there we go.
So nothing new here.
And so let's now move on to the last part,
which are the private methods.
And just like private fields,
they look exactly like the public counterpart,
but with the # symbol.
So remember how we had this approved loan method here,
which was seen more of an internal method
that is used by the request loan
and therefore we do not want to expose this one right here.
Users of this class should only be able to deposit,
withdraw, and see the movements,
and also to request loans, but not to approve them.
So remember, this method here is kind of a fake method.
Fake method that's why it's only returns
simply true right now,
but it could have some complex algorithm
which would determine whether a loan can be approved or not.
And so makes sense to just be an internal method.
And therefore let's just do this.
And so just like that, we converted this public method
to a private method.
Very easy, right?
Let's just, really to make sure, try to run this here,
approve a loan with some value here.
And then indeed, private field.
So here the browser also calls this a private field
must be declared in an enclosing class.
Okay?
Great.
So with this, we just removed this approved loan method
from the public API of our class.
All right. Great.
So just to recap, we talked about public fields,
private fields, and public and private methods.
And then there's also the static version of these four.
So static public fields, static private fields, and so on.
And remember how we actually already used
a static public method here before
in some of the earlier lectures.
And so therefore there is no need
to now implement these static versions of these four again.
So they are usually a lot less important.
And so if you want, you can just easily test these
or implement them yourself.
The only thing you need to know is that static fields
and also static methods are not accessible on the instance,
so in this example on this account.
So they're not inherited from the prototype here
to the class instances.
So instead, they're only accessible on the class itself.
So just again, we just use the static
and then let's call here a test method
which will simply return true.
And so, again, we use this on the account itself.
So now we cannot see anything so let's just console.log.
something here and there we go.
So there is the test,
and, yeah, we use this directly on the account class,
not on the account object that we created through the class.
And if we made this private, then of course, yeah,
we get exactly the same error as before,
but we could then use this here on the inside.
So again, not really that important, I think.
And so yeah,
I'm just not spending a lot of time on this here.
All right.
And with this, I basically showed you
all there is to know about object oriented programming.
There's just one small quality of life,
but also very common improvement
that we can make to these methods.
And so let me show you that in the next lecture.