What do you want to learn?
Skip to main content
Using ES6 in Your Node.js Web Application
by Jonathan Mills
Start CourseBookmarkAdd to Channel
Table of contents
ECMAScript and Node.js
What is EcmaScript?
What is ES6?
Getting to Know KangaX
ES6 Adoption in Node.js
So as we work through this course, it's important to remember and understand the ES6 adoption in NodeJS, and it started with I/O JS, which is now merged back into Node Core, and they broke off from Node for a lot of reasons, but part of it is because they wanted faster adoption of some of these cool new things. And so I/O had some adoption for ES6. When they merged back together, it became Node 4, which confused some people, because it was Node 0 and now it's Node 4, but Node 4 had about 50% adoption, and when we looked at kangax we looked at this a little bit. Node 5 had just a little bit more at 60%, and Node 6 has almost total adoption, almost everything's there in Node. And so what I want you to look for as we go through this course is for each thing that we talk about, I'll put an icon down on the bottom, one of these symbols, Node 4, Node 5, Node 6, or all of those symbols, so you know which versions of Node you need to be running in order to support the feature that we're going to talk about.
Some Syntactic Sugar
This first section of ES6 features that we're going to be talking about are basically just some syntactic sugar. Just some nice little syntax changes that we have that are going to make our lives a little bit easier when it comes to writing code. Nothing earth-shattering, nothing really feature-changing, just some cleaner implementation of some things that we do every day, and a lot of it's just shortcut notation, but it's cool when you get right down to it. And some of the things you can do that used to be even a few lines of code, now you can do just with a couple of key strokes, and it's really, really cool. So let's take just a little bit and look through some of these cool syntax changes that we have in ES6.
So ES6 also provides us with the opposite idea of the rest parameters with the spread operator. And so basically all the spread operator does is it changes an array to a list of CSV. So, the rest parameters took the comma separated values of the parameters and turned it into an array, the spread operator does the opposite thing. So let's take a look at how that works. So basically we have the same thing we were working on in the last clip, we've got a log function that takes the level and an args and just dumps the args out to the console. Well, that's great, right up until I have an array of objects. So let's just do this. Okay, now I've got an array of objects. Well, my function doesn't take an array, it takes a CSV, just comma separated values for the parameters, and so now in order to print that out, I would have to kind of loop over and end up doing something like this and spread it all out so that my logs up top would deal with it appropriately. Well, we have the … syntax to pull it apart, we also have the … syntax to spread everything out. So, if I do this, now I get a CSV or a comma separated values of this list. And so actually if we go and run this real quick, now look, I have an array with a and b. So my args actually spread everything out and do it appropriately. Now there's also another interesting thing we can do with this idea. Let's just create another object called foo. And I want to add this to the front of my object. So, I want to add foo to the front of object, well, there isn't a really super great way to do that in ES5, there's a great way to push it onto the end, but not necessarily to add it to the front. But now I can actually do this, I can say obj = foo, and then obj, because all this is going to do is print out and spread this out into extra commas. So what you end up with essentially is this … object just becomes that. It just kind of blows it out there. And so now when I print this and I run this again, you'll see hey, I've got my object sitting in the front. So that's spread. Spread and rest kind of do opposite things, but in the same way. So up in the parameters it brings commas back together, and down here where I'm passing it in or I'm doing it inside an array, it spreads it back out again.
Object Literal Notation
Probably my favorite shortcut piece of syntax in ES6 is the way object literals are handled now. And it's really simple, just shortcut syntax is really all it is, but it's super cool. So check this out. If you're anything like me, all through your code you have these revealing module pattern things. So, here I've got a greeting service with two methods on it, sayHi and sayBye, and I'll just fold those up. And then you have this return statement, you're returning the object, and so if I just do this, just log the return of the greetingService, you see I have sayHi with a function and sayBye with a function. And this is just normal. We've got it everywhere. Now this repetition sayHi: sayHi, sayBye: sayBye is just kind of dumb, and we're just kind of used to doing it, but now in ES6 we no longer have to. I can just say, hey, I'm going to return sayHi and sayBye and be done, and just have that. And if I run this again, look, see, it still works. So it just knows, hey, if I have a variable named sayHi, I'm going to pull in whatever is in that variable and just name it that. Now I can even take this one step further and just take this entire function and just do that, sayHi console.log, there it is, just like that, and I can take this function, and this is more the way some people do their revealing module pattern, they just kind of lay it out this way, but still it just works. You lay it out, no more colons and explicitly stating what your object literal names are, it just kind of works. So that's the new object literal syntax, it's just simple, straightforward, shortcut syntax, no functionality changes here, it just shortcuts the way that this works and makes it a little bit cleaner and simpler to write things out.
For of Loop
Another cool little shortcut syntax that we have available to us in ES6 is the For Of loop, and it's just a simple way to iterate over an array or string instead of doing the more longhand for loop. Alright, so let's look back at our log function that we've been using kind of throughout this course, and here we've got function login. Now I've actually implemented the for loop, and so this is the standard way to iterate over an array, var i = 0, and I know that I'm not using let, I haven't talked about that yet, that comes later, i is less than args.length, all of those things. Now this is kind of painful, not hugely painful, but just, it's ugly, and I'm introducing a new variable and it's just kind of gross. Well, what we have now is a much simpler way to do this. Now I can just say for item of args. And this is just a variable, it could be anything, but for, we'll just call it, we can even do for i of args, and instead of args i, and I just print i. That is a lot simpler than the other way. And look, it still works. So, for of loops are just a simple little way to print out an array. And like I said, you can even use strings, if I just say of level, so level's just the string debug, I'm going to get each character printed out, right? So, it works in a couple of different ways, and we'll put that back to the right way, but iterating over things is what we do all the time, and just the nice, clean, simple little way to make that happen.
Now the last one we're going to talk about is destructuring, and this one takes a little bit more getting used to, because it's very much a shortcut syntax that doesn't necessarily provide functionality, it just is a way to shortcut pulling out pieces of objects or arrays or things like that. So let's look at this real quick and then I'll show you a practical application that you can look at to see where this might fit. Alright, let's come back to our greetingService for a second. And if we look at our code, so greetingService is returned sayHi or sayBye, if I follow that all back up, notice how we only use the sayHi of our greetingService, and so if greetingService was bigger, I don't necessarily want to carry that around everywhere, I just want the piece that I'm going to use. And so what I actually can do, what I could do is I could just do sayHi = greetingService.sayHi, and only pull in that one thing. And so when I run this, there we go. So everything still works, and I no longer have the entire greetingService being used in my application, it's just this one little thing. Well, this is a little bit convoluted and it's not clean, and so what they've given us is this shortcut method to do exactly this same thing. Instead of putting .sayHi on the end, I can just come over here, add a curly brace, add a curly brace, and now that's going to pull apart the greetingService and add sayHi as a variable with the contents of greetingService.sayHi, which is a longwinded way of saying right here I now have just the sayHi piece of this greetingService, and I can just execute it like that. There we go. Now one of the reasons why this is also a little bit cleaner is because right here inside these curly braces I can also do sayBye. So let's say if greetingService had a whole bunch more stuff in it and I just needed two pieces, well now instead of executing greetingService twice, so if I was going to get .sayBye and then another one that says .sayHi, I can execute it once and pull back both of these variables, and now both of these things work. So another feature of this destructuring is I can give them variable names, I don't have to name them exactly the same thing that's pulling out of our greetingService. So I can just do hi and bye, just like that. There you go. And now that works. So destructuring, all destructuring means is that I can pull pieces out of an object by using this curly brace syntax, and I'll get rid of the sayBye just to make it look a little bit better, we'll pull that over so you see the whole thing, I can just use the curly braces to pull out a piece of an object instead of having to pull back the whole thing. Now, if we play around for just a little bit, this same thing works if I do an array. So if I just want the first piece of an array, now I have pulled this 1 out, and so now you see that's a 1. Or if I want the second piece of an array, I can actually kind of just do that, and now I get the second piece of the array, right? So, destructuring is the same idea as what we were just talking about, but now I'm doing it with an array. So if I have an array of configuration items, or I have an array of whatever it is we want, I could actually just pull them out, I pull out the first three pieces of the array to go do something else with it. So, it works the same way as the object, but now I'm using it in an array format. Alright, so let's look at something real that you might use this in so that it adds just a little bit of context to what we're talking about. So, in this example, I'm going to use my book controller from another course I did, Web Services with Node.js and Express. And in this, I have a goodreadsService, and this service is what's going to go out to an API and pull it back. Well, in this API, or in this service, I have a method called showBook, and I do a module.exports, and I run a function, I execute it, and I pull back this one thing. Well, in my book controller, notice I'm requiring my goodreadsService open and closed parentheses, and I've got my book service here. Now the only thing I use is bookService.showBook, down on line 38, this is it. That's the only thing I use. And so I'm carrying around this entire bookService object, when really I just need the one function. And so what I can do is do this destructuring thing on my require. That basically is going to take what the require that comes back drop just in the showBook object, or variable, and now I can get rid of this, and everything just works. So that's a great example of how you can use destructuring to kind of clean up these big services or these larger things that you have by just pulling out just the piece you need in a cleaner way to drop it in here. Now if I'm only doing one thing, you might say, yeah, just stick it on the end, I could easily just say .showBook here, where this becomes a little bit more convenient is when you have maybe two items. And so I can do showBook and addBook, and then I don't have to worry about all the rest of it. Alright, so that's destructuring in a nutshell. You can make this more complicated if you want to, and you can look at kangax to see all the extra examples of it, but really at its core, this is what destructuring is all about it. It's basically just a way to pull something out of an object or an array into a variable directly. So that's ultimately it.
So that's it for this first piece on just some syntax changes. Now there isn't too much that's earth-shattering here, and no real functionality changes, it's just a cleaner implementation of some things you do already. And with the exception of the multi-variable destructuring that we just talked about in the last clip, you can do all of this stuff in ES5. What ES6 is providing us with is some cleaner implementation or some shortcut notation. So, you can use a for loop and that works just fine, but for of is just a little bit of a cleaner implementation or just kind of a shortcut way to do things. So, hopefully just with this one module, you've seen a whole bunch of stuff that makes sense just to start using ES6, just some quick ES6 shortcuts to make your life a little bit easier. Let's move on now and talk about changes in ES6 that are some functionality changes that will solidify your code a little bit more and make your code a little bit cleaner and more reliable.
A slight variation of the let keyword is the const keyword. And basically what this lets us do is create constants using that same block scoping mentality. So if I create a new variable with const, and let's say I'm doing an env = 'debug.' So that's totally cool. Now if I set env = 'prod,' I'm going to get an error. I'll get a blowup that says, hey, assignment to a constant variable not allowed. So, const is basically just a way for us to create constants, just like most other languages that you've probably played with, you've got an option to create a constant, here you go. Now const is block scoped, so if I say if true, and now I can create a new const called env = change that to 'prod,' and now I've got two different env variables and then I'll print prod, then I'll print debug. There we go. So, const really is just that simple. Cost and variable, block scoped works just the same way let does, except you can't override it again.
So that's it for the variable changes. It's really just that simple. Just a couple of variable changes to help fix some scoping issues with ES6. And that's let being fixed the block scope thing, because most other languages or the languages you've probably been using, .NET, Java, have block scope, and so now ES6 presents us with that block scope option. They also threw in the constant just in that same vein of block scoping, but we now have a constant that we can use to help prevent things from being overwritten. So that's that. Let's pop ahead and look at some function changes that might provide some cool functionality for us as well.
So we'll kick this module off with a conversation about arrow functions, and this new cool little shortcut syntax we have for creating functions. And I say it's cool only because later we're going to talk about some really, really nice implications for services and callbacks and things like that, but let's start out with just a basic conversation about arrow function. So here I've got a function called sum, and it takes two variables, and returns a + b. So, it's really just that simple. And if we run this, you see, we get a 5. That's cool. Now an arrow function basically is going to be this exact same thing, except we're going to do an expression, so var sum =, and then instead of putting function here, we're just going to do this. And now I have a, b, and actually we'll put this all on one line, just there you go, a, b arrow, return a + b, done. Now I've got a function called sum that does exactly that. Now if that was it, then that's not all that super cool, but check this out, if I only have one line, which I do in this case, I can actually get rid of everything around it. If I have more than one line, I need to keep my block, but if I only have one line, now I can shortcut notation that to just a + b and it still works. Same thing, a + b. Now the parentheses on the other side are also kind of optional if you have only one parameter. So let's actually make this square, and my arrow function is going to do that. Now when I run this, I'm going to get a 4. So, arrow functions essentially come down to just a quick little shortcut way of writing a function. And if it's one line and one variable, if you have no curly braces, no parentheses at all, if you have multiple lines or multiple things, it's just a way to eliminate the word function really. So, that's arrow functions. And at this point you might think that's not really all that cool, because honestly it's really not all the cool. Where the cool part of arrow functions comes in is when you're dealing with objects and callbacks and the this keyword. So let's look at a little bit more complicated example so that you can see how arrow functions really start to take off.
Lexical Bindings for this
Aright, now we're going to make things much more complicated with our arrow functions, and I've gone back over and we're back in our GreetingService. But I've changed things up just a little bit. Now I'm using a constructor function, which is why my G is capitalized here, and I've got a GreetingService that's going to be new dot. So back here on line 19, I have gs = new GreetingService jon. And what that does is it creates a new this scope, and it does all that for me, and so now my GreetingService has a this.name, and when I pass the name in, I assign name to this.name. So all that's great. When I do a gs.sayHi, I'll unfold this, I'll console.log my this, just so you can see what's going on, but then I'm also going to do my Hello this.name. And when I run this, you see my GreetingService has the name and my three functions, and then I write out my Hello jon! So that all works great. And as long as we don't go any further than this, we're fine. The problem comes in with a couple of different scenarios, the first one being do you remember when we talked about destructuring? I don't want all of the things around GreetingService, I just want sayHi. So I'm just going to pull sayHi out of my GreetingService. Now when I run it, I'm going to get undefined and look at this, my this is now this huge big thing, and it's the process, it's the Node process that's running. And I get Hello undefined. And the reason for that, if I back up for just a second, the way this is bound is not by closure or anything that happens up inside the GreetingService, this is bound to whatever's on the left side of the dot. So in this case, gs.sayHi, gs is what the this is bound to. When I destructured everything, there's no dot anymore, so this is no longer bound. And you might just say, well, that's a reason not to destructure, and that's cool, but if we set everything back to how it was, we also have an asynchronous version of sayHi, and what this is meant to mimic is when you're calling an API or you're making a database call, or you're doing something like that, well now you have a callback. So, sayHiAsync executes that timeout, that's just to mimic our database call or API or something, and then executes this callback. And this callback also references this.name. And if I do it just exactly the same way I did before, gs.sayHi, but now I do gs.sayHiAsync, now when I run this, same thing happens, Hello undefined, and I get my big process as my this. Now to make matters worse, if I'm doing use strict, now it's even weirder, because I get the timeout this, and it's still undefined. So, everything's kind of weird here, and we don't necessarily like this. So, this is where arrow functions come in very handy. And the reason for that is the way this is bound, because as I said just a second ago, this is bound to whatever's on the left side of the dot, so in this case gs.sayHiAsync, this is the GreetingSerivce. Well, this callback, when this function is executed, when this function right here is executed, there's nothing on the left side of the dot, it's just executed out in the open, so you get the global scope. Now here's what we can do. Arrow functions are bound lexically, so the this keyword in the arrow function binds back to the creating function scope. So I've got a function here, this function, when I use an arrow function, this function becomes the this binding. So if I change this, instead of function, we get rid of function remember, and I just do => and then keep my same function, everything else is exactly the same, I've done nothing different, now when I run this, it's going to work just fine. Hello jon! Boom. And I get my GreetingService. This is a massive game changer for callbacks and things like that, especially when we start talking about classes. And the other advantage too, so that's just with callbacks, now let's do the same thing with my regular old sayHi function, so we'll get rid of the word function, we'll add my arrow, nothing else is different. Now I'm going to destructure, and I'm just going to pull in sayHi. Now when I execute this, boom, same thing, still works. So this is where the arrow functions become hugely helpful. And they kind of open up a whole big series of opportunities when it comes back to using the this keyword, instead of doing a dot bind or some other things, we just use an arrow function in our callbacks to make things a lot simpler and a lot easier for us to do. So, for me personally, I don't use arrow functions everywhere, I just use arrow functions in my callbacks, because especially in my Angular controllers where everything's this bound and it's all bound back, instead of taking a copy of this, so the other way we would have done this in sayHiAsync if this was still a function, right, we totally could have handled this differently, you just take a copy of this. You say var ctrl = this, just like that. If you've written Angular code at all, you've done this, you know you have, right? And then down here you just do ctrl and ctrl and it all works. And that's cool, but it's kind of a hack. And the arrow functions help eliminate our need to do that. So that's arrow functions in a nutshell.
Extends and Super
Now the last thing we're going to talk about in this module on functions is generators. And generators are a cool little way that we can create a function with multiple end points and that you can return back to kind of over time. So let's take a couple of minutes and look at how these things work and what they can do for us. Now the way we make generators work is essentially just create a function. So we say function, and in this case, we'll just say gen. And we're not going to pass anything in yet, we'll add that here in just a minute. So what generators do is have multiple exit points where you can exit the function and then return back to that point and execute it again. So let's create a couple different exit points for this, and then we can go. And the way you do that is with the yield statement. In a regular function we return, well, in a generator we do a yield, and in this case, we're just going to do a yield of 1. And let's do maybe just one more. Yield of 1 and yield of 2. Now there's only one other thing we have to do for this function in order to say, hey, this is a generator function, and we're going to add an asterisk right there, and that is what denotes this is a generator. And so a lot of times what you'd have is you'd do stuff, you'd yield, then you'd wait, and then you'd do more stuff, and then you'd yield some more. So the way you run a generator is you create a variable. So we'll just call it it for iterator, and that's kind of essentially what this is, and you'll see that as we build through it, but I'm just going call it it for now, and it's going to be gen, and we're going to execute that function. Now that I've executed that function, it doesn't really do anything yet, I actually have to call one more thing to make this work. And what I want to do is I'm just going to print out, it.next, and we execute that. Now when I run this, check this out, I get the value 1 and a done of false. And the 1 came from this yield. So here I did yield 1 and that was my result, and the done false means hey, there's more stuff. So you know what? Let's run this again. And just looking at it should be obvious, the return for the next ______next call is going to be 2, right? So now we'll get a 1 and we'll get a 2. Still a done equals false, and that's because we have two yields. Now, it looks like we're done because, hey, I only have two yields, but we're not actually done until the function exits normally. So let's add one more of these, and now when I run it, I get 1, 2, and then a value of undefined. Done is true. So now the function is executed all the way through, it executed 1 and executed 2, and then it just needed somebody to say hey, now we're done. Okay, now one cool thing about generators is they're going to be two-way conversations. Like, I can initialize my generator by passing in something in here. So let's do that, let's just pass in Init, and we've got a parameter on our function called input. And let's just output our input. So, yield is going to be our input. Alright, now if I delete everything, when you're doing a generator, these first 2 statements, line 10 and 11, always go together, because it doesn't actually do anything until you call it.next. So you create the iterator and then you call next. And so what we're going to get now is our input, right? So value Init, done. So that's the starting point, but now I can do this, var netIn = yield. So, on my next call, I can pass in something. We'll just say NextInput. So when this yield right here gets executed, I exit right here. Now I'm sitting on line 12. Then my next, my it.next, whatever parameters I pass in here, will be added for my yield, and so netIn becomes NextInput. When I call my console.log here, I'm actually going to get this NextInput. Well, I'm not, because I actually have to use it. Boom. There we go, Init, NextInput. So that allows us to have a simple two-way conversation between our function and the execution of the function. And now let's look at something that may be a little bit more complicated that we can do using generators and maybe a repository.
Repository as a Generator
So now I have a book repository, and in this book repository I've got a list of books, and it's just books with various titles. And I'm returning my list when I execute my bookRepo, and that's all cool, but I can use generators to control the flow of books from the repository into my controlling application, and this is just one example of the types of things you might be able to do with a generator. And so let's turn this into a generator, and let's say hey, I want the first two items from my list. And so now we have a parameter being passed in called, let's just say num, let's just call it num, and that's the number of items I want returned. And then we can just loop, we can create an outbound array, and then loop over our list and push the item on until we have as many as we asked for, and then do a yield out. So look at line 22 right here, I'm yielding my out array, so that's my list of books that I'm done with, and then I'm taking another number, so basically starting over. So, I'm overriding num with something new, and then I'm erasing my out array. So, check this out, let's see what this looks like. So, I've got my repo = bookRepo, and then my initial repo.next, and we're going to execute that. Now when I run this, notice I've got two, 'War and Peace' and 'Wind in the Willows' with done equals false. So I got two books back. Now when I run this a second time, and let's say this time I'm going to run it with 4. So hey, I got my first two, now give me four more, and I can control how many I want back. Now when I call repo.next 4, the function has stopped right here on line 22, I'm in a holding pattern right there, and I'm not going to do anything in this function until next is called, and when next is called, this 4 is set to num, and then I overwrite my out, and I start my loop again, I don't start it again, I continue my loop where I left off, except now out is empty. And so now when I do 4, I'm going to get the next 4 books in my list. So, the first time I run it I get my 'War and Peace' and 'Wind in the Willows,' and then I get four more books. So, now when I call this again with four more, now I only have seven total in my list, there's only seven books in this list. So when I call four more, I'm going to start over, four yield out. Well, my if's never get execute, because I'm going to loop over. And so what I want to do down here instead of a return, I'm going to do my final yield, and I'm going to yield out. And now I'm only going to get just a couple items, except i before e, yield, there we go. So I get two the first time, four the second time, one the last time, and done equals false. And so if I executed this again, then I'd get my done equals true. Now this is just a simple example of how I can take a repository or something like that and control the flow of items coming out of that repository with, hey, give me two, hey, give me four, hey, give me two more, give me my next group, and have the repository only loop over and hand back the things that it needs. So one example of where generators can be interesting. Now, you can do this in other ways, this isn't earth-shattering, this isn't something you couldn't accomplish in some other way, especially with closures and saving things outside of your function, but this is just a nice little concise way to get something like this to work.
Alright, so that's our module on functions. And we started with the conversation about arrow functions, and how the this in arrow functions are lexically bound, which makes the this keyword for callbacks especially. So if I'm doing callbacks involving this, arrow functions save us a lot of heartache, because this is now bound "correctly," correctly in air quotes, so that it does what I expect. So arrow functions are fantastic for those callback areas where I want things to line up the way I expect them. We talked about classes and how classes are not what you're used to, they're a little bit different in some subtle areas that may or may not work for you, and so that's kind of up to you now that you know what classes are doing and kind of how they work, you can make the decision for yourself whether or not classes are an ES6 feature you're going to use or something you're going to kind of pass on. But we also talked about inheritance with classes and the extends keyword and the super keyword and how all of that stuff works, and that can be kind of cool, it's nice little syntactic sugar sitting on top of the way objects work. And then we ended with a conversation on generators, and generators are just kind of this cool neat little thing that allows you to interrupt execution of a function and hand something back to the calling procedure and then maybe get some feedback before you continue and do more things.
So the first thing we're going to talk about in our built-in module is sets, and sets are kind of an array-like object that stores an ordered list of items. And really it's easiest to understand this once we kind of start playing with it. So let's just build something out, and then we can see what we've got. So, in order to get a set, we're going to do var items = new Set. Now you have to do new when dealing with a set, so this is an object that its own thing, and we create it with the new keyword. So now I've got a new set, and I can add items to my set using add. So, items.add, and I can add something to this. So let's just add, let's just say a 4. And then I can see, I can look into my set with two different keywords, so the first one is, and we'll just console.log this, the first one would be items.size, and this is how we know how big a set is, and in this case, items.size is going to be one, one thing. The other way we look into this is with has, and this is the cool strong part of the set versus just an array or something like that, I can actually say items.has and check to see whether or not this list has a specific item in it. Now when I run this, I get 1, for I have 1 item in my list, and it does have 4. There's a couple things about a set that we want to look at real quick. First and foremost, notice I've stuck a string in there, 4. I could also put a number in there, in this case, let's just do 4. And what you'll notice is that I can do both 4s. A set does not check or does not type an item when you're adding it to the list. So if I have a number 4 and a string 4, it's going to allow both of those things in. When I run that now, notice I've got two items in my list. However, if I try and add 4 again, it's not going to take it. Now I still only have two items. So this is an ordered list, but it's a unique ordered list, so I can only add things that are not already in there. And notice it didn't give me an error, it just didn't do anything with it, which is kind of awesome. Okay, so I can also do this. I can pass in an array of other things when my new and now I'll have the four items from the original, plus the two more, so I'll have six items total. And I can do my item.has and all that kind of stuff. Now, a list that I could only get to with checking to see whether or not an item exists is one thing, and that's kind of useful, but I can also iterate over this, and this is where it starts to become a little bit helpful. So I can do for, let item of items, using our ES6 of loop, cl item. So check this out, now there's my list. My 6 and my true came from before, but then 5, 6, 7, 8, 4 the string and then 4 the integer are all there. Okay, so this is a real quick look at sets. And if you are trying to keep a list of maybe keys for an object or things that you're using here and there, you can add those items into a list or a set and then just check to see if something's already in there. So, if items already has 4, then I'm not going to do something. If my list already does have 4, then I can do something else. Now one last thing to look at is the clear. So I can do an items.clear to empty out my set. There you go. Now everything's empty, because I did my clear right here. Alrightt, so that's just a quick look at sets so we can kind of get an idea of another type of object that we can use if we're trying to keep track of an ordered list of items. Alright, I can't talk about sets without also talking about weak sets, because they kind of have the same name, they both have sets in them, but weak has kind of a weird connotation to it. So I want to talk through a little bit what a weak set is and how that compares to a Set. Now remember, everything that we talked about with a set we used integers and strings and in a weak set we can't do that. Weak sets are only about objects, and so you have to have an object that you're adding into your set. And so here what we've got is a new set, so I'm still with the set for just a minute, and I've got two objects I'm adding, x and y. And then inside my if statement, I have a third object, I let x = baz, and so if you've been paying attention up till now, let is block scoped. So inside our if statement is the only place that this object exists. Outside of this if statement, this object no longer exists. If I add this object to my set, and then I iterate over my set, that object is going to show up inside my list. So if I run this, notice how I still have my baz 1, 2, 3, inside my set, even though the scope of that object no longer exists. And so that's something that a set does that a weak set's going to kind of think. If I go with WeakSet, if you have a list of objects that you're trying to keep track of and just know, hey, does this object exist or not, have I messed with this object yet, WeakSets are perfect for that, because they're going to be truly inside what's in scope and what exists and what doesn't exist. So right now this WeakSet, when I run this, we're going to have one problem, and I'll explain that to you in just a second, but at the end of this, I'll only have two items. So here we go, let's walk through what the WeakSet does. So, var x, var y, it's all added in, at this moment, when I get to line 11, this x baz 123 exists, it's totally in my WeakSet. When I leave scope, that gets garbage collected, and it's gone from my WeakSet. Now there's a limitation to my WeakSet, because I can no longer look at the size of the WeakSet, and I can't iterate over my WeakSet, because it's only kind of loosely coupled, like things are only loosely in the set, and it keeps track of them only kind of, so that it allows for garbage collection, I mean, that's the big piece of this whole thing is for it to allow garbage collection. So I can't do this, I can't iterate over it anymore, all I can do is see if an item has, so let's do cl items.has. And in this case, we'll do y just so you can kind of see how this works. So notice I do have, so line 11, I do have x in there for baz 123, but there's no way for me to even get to this baz 123 anymore after I leave my if, because that x is no longer in scope. So WeakSets are kind of that thing where if you need them, and you have memory issues around keeping track of objects in a set, WeakSets are exactly what you want. Other than that, you're probably never going to use them. But I wanted to take a minute and talk about the difference between sets and WeakSets, just so we're all on the same page.
So really that's it. That's the vast majority of the stuff that's going to be available for you, especially in the Node environment for ES6. And remember, it's just a set of cool new features, and we talked about a lot of stuff over this course, and there's a lot of things that you can pick up and use right now in your applications, especially things like promises or template literals or things like that, arrow functions especially to fix our this problem, but you can just pick and choose. There's lots to pick from, but you don't have to use them all. Pick the ones that make sense for you, and start playing around with those, and remember kangax is your friend. There's a lot of other things out there that we didn't really talk about, and mostly because they're not going to be as relevant to you necessarily in the Node environment, but kangax is your friend. Go out there, check out kangax, and see if there's anything else that you might want to pick out and play with, and remember kangax also shows implementation, just kind of hover over the question mark, and that'll get you done. Thanks a lot for hanging out with us over the course of this course. If you have any questions, don't forget to drop down to the discussion and we can check you out there. And we'll talk and answer questions down in discussion. Thanks a lot.
Released10 Aug 2016