Check out a free preview of the full JavaScript Design Patterns for Web Apps course
The "Creating the Data Classes" Lesson is part of the full, JavaScript Design Patterns for Web Apps course featured in this preview video. Here's what you'd learn in this lesson:
Max creates TodoItem and TodoList classes. The TodoList class implements the Singleton pattern, so only one instance of the list can be instantiated in the application. The observer Mixin is imported and applied to the TodoList class.
Transcript from the "Creating the Data Classes" Lesson
[00:00:00]
>> Maximiliano Firtman: Let's create the classes, including the one that will use the mixin, okay? So, for that, I'm going to create another JavaScript file, I can call this classes.js. I know if you're coming from Java or C# it looks so dirty. We're going to create two classes, one for the todo item, one todo, and then another class that is the list of todos, the list of items, okay, two classes.
[00:00:29]
In two classes, these are two classes, they are not so big, so I think that we can just put them together in one file. It's not a big deal, we don't need to follow Java guidelines. In Java, every class should be in a separate file, okay? But this is not Java, we are in JavaScript.
[00:00:46]
So, we can create the class TodoItem that will just include a text, it's just a text for now. Later, you can add more properties, okay, but for now, it's just a text. I'm going to just save my text in a property, and I will use equals (other), return this.text = other.text, what is this?
[00:01:12]
This is actually very similar, not 100% to the value object pattern, I'm sure, if you remember that one. Actually, if I'm adding twice the same todo, so I need to get lunch and then I add again get lunch. It's the same action, right? So I shouldn't add it again, does that make sense?
[00:01:34]
So we can kind of think on the value object, like the chudo text, it's a value object, I shouldn't have duplicates, it doesn't make any sense. Have lunch, is have lunch so I shouldn't have two have lunch, that makes sense. So that's why it's just a equals method that will check if my text is equal to another todo.
[00:01:59]
And if it's like that, then I'm not going to add it to the list, yeah.
>> Speaker 1: In a situation like this, I would typically reach for the set data type. I assume you're not using that just cuz it's a teaching example, or are there other considerations?
>> Maximiliano Firtman: There are other concepts, what happens with the set?
[00:02:16]
So, if I have let's do this I have a set, new set. And then I say, S, I'm going to add a new object with a text A. Then I'm going to add another object with a text A. What happens with that, will it add it or not?
[00:02:37]
>> Speaker 2: It will add it.
>> Maximiliano Firtman: It will add it, why? Because it's a different object, it's a different leader, even if it has the same text. Value object the design pattern is actually solving that problem. It's actually saying, okay, so yeah, we are talking about two different objects but the values inside are the same.
[00:02:55]
It's a different object but because the values inside are the same we should treat them as the same object, even if they are not the same object, okay? Cool, so, that's the TodoItem, actually. It's pretty simple, it just has one property, constructor receiving the property, and the equals that we will use later for emulating this Value object pattern.
[00:03:21]
Now let's go into the TodoList. So the TodoList will include all the data. And I'm going to set my data as a set as well, I can use an array. By the way, do you all know what this syntax is, the hash prefix?
>> Speaker 3: To make it a private.
[00:03:45]
>> Maximiliano Firtman: It's a private property, a private field, actually, that's a term in ECMAscript, in JavaScript, so that means it's private, I cannot access data from the outside. So I'm gonna say it's a new set. And then I can, get because from the outside, maybe I wanna get the items at some point, I'm going to create the property with the getter called items,and it will just return this.data.
[00:04:15]
Remember to add the hash. So now I can access from the outside, you may be thinking, well, why don't you create the public property directly? Well, it's a good design pattern to keep separate the public interface from the data itself of in the future, in the future, I may want to change this.
[00:04:37]
So in the future, I may want to say, well, maybe. I need to go and grab the data first from a database, I don't know, whatever. So for future proof, it's better to create the getter. Of course, that by the way, when you're doing this from the outside, you create a new TodoList something like this, and then you just call items as a property.
[00:05:03]
Just in case you haven't played with getters, it's not even if it's a function, I'm treating it as a field as a property, and it's going to execute the function, and the function returns the data. Okay, make sense? Cool now, this is a TodoList, this is the list that will hold all my data.
[00:05:25]
I don't want to have multiple instances. At least this web app at this point. It doesn't contain separate list producer or work and personal stuff. It's just one TodoList, okay? One and only one, because it's one and only one I don't want anyone to create a new TodoList add some elements to the list and then if you create a new one it's empty.
[00:05:54]
So I want it to be one and only one so it's a candidate for a Singleton, does that make sense? So I want to apply Singleton to the to the TodoList. I only want one TodoList, I don't need more than one. If someone can create another one, it's actually a problem.
[00:06:14]
Okay, so if you remember from the slides, when I was explaining Singleton, I mentioned that the simple. Simplest way to implement the Singleton, just create an object literal. But here I'm going to use a different approach, it's a class, okay? So we will try to see how one way, because there are JavaScript, there are always many ways to solve the same problem.
[00:06:35]
One way to implement my Singleton. So we can kind of following, in case you have ever played with Singleton in Java, I'm going to start copying the Java part, and then we will get out of the Java way. So for that, I can create a static property called instance that it wants to start as null in modern JavaScript.
[00:07:01]
We can also use the static prefix to specify that a property is static, which means it's a class field, not an instance field. So there will be one instance per TodoList, okay? Then I'm going to create a static in it block code that is also new. In ECMAScript, that that code will be executed whenever the class is parsed.
[00:07:28]
When the class is parsed, even if you are not creating any object for the class, the static code block will be executed. And it will be executed only once per project, for web app execution So in this case, I will create a new to the list. So this is creating the actual instance and saving that as a static property.
[00:07:51]
Then I will need a method get instance. I mean, I don't need the getter, but I can just access the instance. But I think just having it together is a good idea. If you see the code, this is similar on how you implement this in Java. It's called instant, getInstance, it's the same idea.
[00:08:18]
But I still have a problem because, yeah, what's the idea, now I can create here a variable and say my todoList = TodoList.getInstance, right? That's idea of creating a static method. So this is going to execute this method, okay? Okay, cool, if I create another todoList and call getInstance, I'm still getting the same todoList.
[00:08:55]
Do you all follow that? So every time I'm calling get.Instance, I'm getting the one and only instance available. What's the problem that we still have here? I can create a new one like this and what happens if I do this? Am I getting the same instance or a different one?
[00:09:18]
>> Maximiliano Firtman: A different one, because I cannot not force the class to avoid the execution. But something that we can do is create a constructor and here we can throw an error, saying, hey hey, Use TodoList get.Instance() to access the list. So we can throw an error. Now, no one can create a new option.
[00:09:59]
>> Maximiliano Firtman: Okay, any questions? It is not ready yet.
>> Speaker 3: Does constructor have to be after a new todoList and the static?
>> Maximiliano Firtman: So you mentioned about the order, it doesn't matter. I mean, if your brain is happier with putting it like this, but the order doesn't matter. So, but let's put it within Singleton anyway.
[00:10:21]
However, if I try this, it's not gonna work, why? Because no one can create a new instance. Not even myself in the static code block. So when I'm trying to create the instance, the one and only instance, it will throw an error. So something a little hacky, but yeah, it is what it is.
[00:10:39]
I can just check. If I do have in a static instance so basically this will try just let's try to follow what's going on here so the first time you execute you're the. The web app, the instance is null, okay? So then the static code block is going to be executed, and this one is creating a new todoList so it's creating an instance.
[00:11:13]
When it's inflating this object, it goes through the constructor. And the constructor says, do we already have an instance? No, it's null, because it's null, it's not going to throw the error. It will let me create the instance and now I will save that instance in my static variable, makes sense?
[00:11:42]
So it works. Next time I'm trying to create a new one. Now, instance does exist, so I throw in the error, does that make sense? I mean, it looks either hacky, but that that's a way. I mean, simply I should create an object, a literal object, but it's a way to still use classes and all the advantages of classes, but in this case we are forcing a real Singleton.
[00:12:13]
By the way, right now this class has a Singleton. Let's remove the candidate. And remember that we also wanted to apply the mixin. How to apply the mixin to this class? To apply the mixin, we can use object assign and where is. First we need to pass the object where we going to apply the mixin.
[00:12:35]
And initially you think that we want to apply To the class. But that's not the case. I'm not sure, do you know what the type of a class is in in JavaScript?
>> Speaker 1: Function?
>> Maximiliano Firtman: It's a function, correct. So a class is actually a function, and which it's weird, yeah, but this is for historical reasons.
[00:13:00]
If I'm doing this, I'm going to add the mixin to the function that constructs the object of the class. That's not what I want. So I wanna change the prototype. And again, we don't have enough time today to explain prototyping in JavaScript, but actually this will add the mixin behavior to all the instances of the class.
[00:13:28]
Now, by the way, we know there is only one instance in this example, but anyway, because it's a Singleton. And I'm going to apply the observerMixin. What's the problem? My observerMixin is written in a different module, right? The problem is that that mixin should be exported. So I need to export the mixin, if not, I won't be able to use it from the other model, okay, makes sense?
[00:14:00]
And now that I exported it, I need to import the observerMixin. So if you ask the ID todo that, so I select this from the order complete. It's adding me the import, but there is a big problem with VS code and vanilla JavaScript projects, if you execute this, we will get a 404 HTTP error.
[00:14:26]
>> Speaker 2: Because it doesn't have the file type.
>> Maximiliano Firtman: Because it doesn't contain the extension. It says, load this from mixin, but it's actually mixing.js. When we're doing vanilla JavaScript projects, client-side, it's the browser making HTTP requests. The browser needs to have the full qualified URL. And the problem is that we're used to Babel, TypeScript, and other builders that helps us with that.
[00:14:59]
And then we don't need to use.js when we are using those builders. And of course, they transpile our code, and they will finally add the .js, okay? But VS code by default, it's kind of thinking that we will use Babel or any other builder, so it's not adding the .js.
[00:15:20]
So be careful with that. Okay, so we need to import this from ./mixin.js, so now we can actually apply and it will work, okay. And this is then applying the observerMixin to the,
>> Maximiliano Firtman: So now my TodoList will also have the methods of the mixin, notify, add observer, remove observer.
[00:15:50]
Automagically, we injected that behavior and also the set for the observers.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops