ES6 for AngularJS – Angular Lunch

A few months ago, Oasis Digital started a monthly St. Louis Angular Lunch. At the November 2014 lunch, we had a guest speaker: Mark Volkmann of OCI. Mark talked about ES6 and the Traceur compiler, and briefly how they fit in to developing Angular applications today.

Transcript

We have transcribed the talk about to text, provided below. This is a rough, first-draft transcription, so any errors are probably from that process.

1-Email.png

Mark Volkmann: I'm starting with this email saying what I'm supposed to do, so you can remind me if I leave out something here. I'm going to briefly introduce ES6. That is really tough to do. I have enough slides here that I could talk about this for at least an hour and a half, and not even mention Angular.

I'll try to hit some of the high points and the features that I've actually been using with my Angular code. I'm going to show how to integrate it into a build process. I have a GitHub repo with examples in both Grunt and Gulp.

Then I'll talk about some of the reasons why I think it's good to use these features with Angular. That will prepare you for using Angular 2.0. But I'm not going to talk about Angular 2.0 at all. Very controversial subject and open to some future changes. It's probably best to avoid that for now.

2-ECMAScript.png

All of these slides are here for the purpose of teaching a JavaScript class where I want to go into all of these details. But since we're short on time today, I'm going to skip a fair amount of these. We don't need to talk about what TC39 is and the standards body.

3-ES5 vs ES6.png

But I do want to mention that ES6 is a superset of ES5. So everything you've learned about ES5 still applies, although some things you wouldn't use as much if you're going to use the ES6 features. But ES5 did not introduce new syntax. ES6 does introduce a fair amount of new syntax.

4-ES6 Features.png

Here is a laundry list of the things that are in ES6. It's not finalized yet. I guess, the features — that is finalized, but some details about some of these things might still be in flux for a few more months.

5-Transpiler.png

A transpiler – some people really hate this term. The way it's been described to me, the difference between a transpiler and a compiler is that a compiler reads in source code in some language and turns it into some other language. Like Java going to byte code. A compiler does that; whereas a transpiler is reading in code in some language and compiling it into the same language. So if you're going from one version of JavaScript to another version of JavaScript, some people will say that's not a compiler; it's a transpiler. But maybe, that's a debatable thing. But when you hear that term, that's usually what people mean.

6-ES6 Transpiler.png

There are many of these transpilers that can go from ES6 to ES5. I'm going to talk quite a bit about Traceur from Google. That's the one that we're using on my project that matters right now.

I've tried some of the others, and they all have various issues with them. One issue might be that it doesn't support source maps. That's kind of a big deal because if you don't have source maps being generated, then that means that the code you'll be looking at in the browser debugger is the generated ES5 code. When there is a problem and you're stepping through, you won't actually be seeing the code that you wrote. You'll be seeing the generated code. That's okay if you're tracking down some problems, but it's better if you can look at the actual code that you wrote. That's one issue.

The other issue is the transpilers support a very small subset of ES6, and you want to use as much as you can. From the ones up here, it seems clear to me that the best ones are Traceur and 6to5. Now 6to5 touts as one of their advantages that they don't have a requirement for any runtime library. There's not a separate JavaScript file that you have to pull into your app to use it. I would say that's not necessarily a benefit. You could look at that as a bad thing.

Traceur does require a runtime library and what you get from that is that they can support things like new classes — like a new set class and a new map class that's added in ES6. 6to5 isn't going to give you that because they're just doing syntax kinds of things and going from ES6 syntax to ES5 syntax. So I don't mind having this extra runtime dependency to pick up as many features as possible.

7-Use ES6 Today?.png

It may take a long time before all the popular browsers have a good set of these ES6 features. They're coming along quickly. But I would say that even if they catch up quickly, it's not going to be the end of the story. Because what's next? It's ES7, and then ES8.

I have this feeling that we're always going to be in this situation: that there's a feature coming to JavaScript that you would like to use today and you're not using it because some browser doesn't support it. So I wouldn't look at this introduction of a build step — to convert your JavaScript code to something the browser understands — as something you're just going to do for a little while and then you're done with that. I think we may be in this situation for the long-term, and maybe forever. As long as there's new features coming and the browser doesn't natively support it but you want to use it, anyway.

A good place to see a summary of support for these features is this kangax compatibility table. Here you'll see a list — down the side — of ES6 features and here you see different browser versions, including Traceur. And then, you go down the list and see what the support is for that. It's even more detailed since I took this screenshot. Now instead of just saying "Yes" or "No", it will say something like "7 out of 8", because there's eight aspects of this feature and they've got seven of them covered. You're going to expand this thing and see exactly what it is that they don't handle yet. So it's not just green and red; it's shades in between now.

8-Google Traceur.png

Google Traceur. I think it's the most capable one of these transpilers that you could use. It is implemented itself in ES6 and so they use Traceur to compile that down to ES5. There's an online REPL tool that you can use just to try out different things, and I'm going to show some code running in that REPL a bit later.

You type in code in ES6 on the left side and it shows you the result on the right side. Interesting way. It doesn't run the code. It just shows what the translation would be so you can get an idea of what's happening.

You can install this thing with npm and run it from the command line. There is a way that you can do the transpilation right there. But you'll probably want to use a build tool like Grunt or Gulp to do this.

In our project, we make it so that we leave the build tool running all the time and it's watching our files. And if you save a change to a file from any editor, then it's going to do that transformation for you. We do that with Less for CSS, and the same thing with our JavaScript code.

But notice the big red box down there: that was one thing that kept us from using Traceur a few months ago. Because we were still wanting to support IE8, and you can't do that with Traceur. The reason is that their runtime file that you have to include in uses some syntax features that IE8 doesn't support. So it can't understand the JavaScript in the runtime file. Fortunately for our project, we no longer have to support IE8, so we're back to using this. In the interim, we were using 6to5 for a while, and that's certainly better than nothing at all.

9-Running Traceur.png

I have information on this slide about how to use Traceur from the command line and ask for help. But the main thing I want to point out here is that there's a small set of features that Traceur supports that they consider experimental. And you can't use those unless you use the steps to add experimental flag. We're doing that currently.

10-Source Maps.png

I talked about source maps already. This option –source-maps causes it to generate the codes and so you get two files for every JavaScript file. And the browser, it's looking for this.

11-Using source maps.png

In order to use source maps, there's a few things you have to check for in Chrome. You open up Developer Tools and there's a gear icon in the upper right. Then you want to check the "Search in content scripts" and "Enable JavaScript source maps." It's really an important one. When you go to the Sources tab, you actually see both of the JavaScript files there for each of your JavaScript files. You'll see the original one and then the ES5 one that was generated. It's up to you to select the correct one, to select the ES6 ones that could step through that code. So you have a choice. If you want to step through the generated code, you could do that. Or you could step through ES6 code instead.

Firefox is similar, with the gear icon that you go to to get to debugger option. And then you have to say that you want to show the original sources. There you don't see both, you're either seeing the transpiled code or the original code.

Audience Member: How good is the generated code?

Mark: Now that's another big difference between 6to5 and Traceur. 6to5 prides itself on generating code that is very close to the original, so that if you look at that, it will look very straightforward. You can understand the mapping. Traceur doesn't care about that as much. They're more after correctness and, maybe, efficiency. I'll show you an example coming up of the result of transpiling these components. In some cases, it looks pretty weird, what it generated for you. So you'll really appreciate being able to step through the original code instead of what it created. Yes, but 6to5 does a better job of generating readable code.

12-Linting.png

I think it's really important to do linting of your JavaScript code. There are a lot of tools you could consider for this: JSLint, JSHint, ESLint. The reason I'm talking about this here is that we need to discuss support for ES6 features. Because you probably don't want to start using ES6 if you can't do any linting at all, you know.

That is the case with JSLint. There is no indication when — or if ever — they're going to support ES6 features. ESLint plans to; they've stated that but they haven’t done[a][b] it yet. So that leaves us with JSHint. It's the only one that has decent support for that. You have to set the esnext option, and then it recognizes a large subset of the ES6 features, not all of them. So my guideline here is that I don't really want to use features that I can't lint, so I try not to do things that will fail that.

13-Automation.png

You can automate this with Grunt and Gulp. A big thing here is the watch and the livereload features, for me. You can do both of those things in Gulp also. You set this up so that it's looking at a directory of all your JavaScript files, and it can be a deeply nested directory. Then you tell it: maybe you have a build directory, and you wanted to put the generated code over there. And as I've said, you could use any editor or IEE. When it sees that you've changed the file, it will automatically transpile that into ES5 code. Let me show you some examples of how you do that.

14-gulp-traceur-demo.png

I have a GitHub repo and it's called gulp-traceur-demo. This label — because, originally, I was just going to try out Gulp. But then I added a Grunt here, as well. In fact, let's start with a Gruntfile.

15-traceur-simple code.png

I'm using a module called traceur-simple, I think. If you've used Grunt before, this will look familiar. If not, it's not really that bad. In this initConfig setting, I'm setting up two things: clean so that I can blow away all the generated files, then a traceur and I'm setting some options. I mentioned both of these earlier: I want to be able to use experimental features in Traceur and I want to generate the source maps.

And then I taught it where to look for the files, I look in my source directory. This is a very simplified example where there's just one JavaScript file: it's demo.js and it's going to fit the resulting file there. That's it. You should be able to easily take this example and expand it to fit your project.

Audience Member: Do you ever need to list more than your main file?

Mark: That's a good point. If you choose to use ES6 modules, then your main JavaScript file is going to import things in the others and those might import even more. In that case, you just have to worry about the main one and it will see your imports and take care of everything for you. A weird thing about this is that that means that the generated ES5 code is all in a single file. However, the source map remembers the original files, so you would see all of those in the debugger. You can pick the individual files and step through them. But you just get the one generated file.

But a downside of that — in the development environment — is that that means every time Traceur runs, it's now slower, because you are transpiling all of your code every time you change any file. So we are not doing that right now.

Audience Member: Mark, follow-up question specifically about the Traceur configuration using the experimental flag there. Is that experimental as in Traceur itself has experimental support for an ES6 feature, or the ES6 feature itself is still an experimental one or not yet standardized?

Mark: It can mean both. And it can also mean that this is a feature that's not even in ES6, it's actually in ES7. For example, the async and await keywords, great things, very synchronous codes. You can use them today, but you have to set that experimental feature.

16-Gulp-file code.png

Here's my Gulp file doing the same sort of thing. I'm calling in the gulp-sourcemaps. Since it's a separate thing in the Gulp world, they've decided that each thing that wants to work with source maps doesn't need to handle that itself. There's a separate Gulp module just for that.

gulp-traceur. In their example on the website for this gulp-traceur plugin, they show using concat so that they can concatenate the results of all of the generated code. I didn't want to do that, so I have that commented out here and I have it commented out there.

But otherwise, this matches what's on their website, except for one thing: this string here where I'm passing a dot. In the example on their website, they don't have that and I swear it does not work. That's the reason I created this kit of repo in the first place. It's to report this problem and to try to get the author of that plugin to test that out. He's not talking to me.

Audience Member: This is an old script. I can tell because it uses rimraf. rimraf is, politely, deprecated; less politely, it is a terrible piece of crud.

Mark: I was using another, there's a clean plugin; it was deprecated, use rimraf.

Audience Member: In the Node world, everything's changing all the time.

Audience Member: rimraf bites you very badly. It's a great name but it's a terrible plugin.

Mark: So like the Grunt build file, you could customize this one to meet the needs of your project.

17-gulp-traceur-demo.png

I've got all the files here and the steps for how to actually run this. You could test out debugging using the source maps.

18-block scope.png

Okay, I'm going to go through some of the ES6 features. First one is block scope. Rather than have all the variables inside the function get hoisted up to the top, if they're declared inside a block like an if statement or a loop, then they're scoped to that block if you use the let keyword. There's also a const keyword. I don't want to spend too much time on this.

19-2nd block scope.png

But a similar thing happens is that a function that you declare, they are inside a block or scoped to that block, and they don't get hoisted up to the top of the function that they're inside.

I'm going to skip symbols for now.

20-Modules.png

Let's talk about modules. There are a couple of ways that you can identify that something is a module. One way is: In your HTML is a new <module> tag, and any JavaScript code inside that is considered to be a module. I really don't think that that's going to be used that commonly.

We'll see an example of a module coming up that doesn't use that. A module, typically, is going to export some things because if it doesn't, it's not sharing anything. It might have some side effects but the way they share something out of a module is to export it. You don't wrap the content of the JavaScript code in that file in anything special. So in that sense, it's very much like Node.js where a single JavaScript file — everything in it is private to that file unless it gets exported in some way. So you don't have to worry about top-level things becoming global.

Modules are evaluated in strict mode by default, so you don't have to say "use strict"; and supports cyclic dependencies, so it's okay for Module A to depend on B, B on C, C on A.

This is going to make it so that the way to write something that has an API like JQuery or the Underscore libraries — and they pick something that's going to be the global variable like $ sign or the underscore character, and they may attach a bunch of functions to that — they all have to do that with modules. Future versions of JQuery and Underscore repo would be bound to do that.

I don't need to use objects as a namespace — like JSON, which has stringify and parse; and Math, that has all those functions. So I just create a map module and when people import it, they'll get to choose what name they want to use for accessing all of those functions.

21-Modules-Exporting.png

Let's talk about how you export things from a module. One way is: On the same line where you're declaring something — like a variable or a function or a class — you can just put export in front of that. And now that's available outside.

You also can just define all of your things — all your variables and functions and classes — and then later, maybe at the bottom of your file, you can say export. And give a list of names of things that you've already defined that you want to export. While you [are] doing it you can say, "Well, that name that I gave it in this file, I really don't want to export it with this name. I'm going to export it as some other name." That's an option that you can use.

You also can specify default export. This is, I think, somewhat controversial and makes the syntax more complicated to talk about than it would be otherwise. But you can say, "I'm going to export a bunch of things but one of them I consider to be the most important thing." People just want to import the default thing. They can do that without having to know a name for this thing. You can say, "I want to export this value as my one default." I could still have all these other exports and people can get to them, but there's one that I have identified as the default. Now if this value has a name associated with it and the value of that name is that, then this line is really doing the same thing. And here's how I could say that some function I'm defining is going to be my default, or some class I'm defining is my default.

22-Modules-Importing.png

We'll see on the next slide: On the other side, when I want to import things, how is it different based on whether I have names of things or whether I have a default one? If I say "Import everything as some object from this module-path," then it takes everything that was exported and it makes those be properties on this name. That will be like a local object that we have now and it can get to everything. And notice that it's read-only, these things that I have imported.

I also can say, "Well, I know that module exports some things with certain names, and I don't want all of them. So I'm going to give you a list of the ones that I want to use." And if they called it foo but I want to call it var, I can say "I want to give it a different name inside my file."

If I want the default, I could say "What name do I want to use for referencing that default thing in my file?" And then just pull it in. You could see the difference here is that I have less syntax — no curly braces, I don't have to use this as and some other name. By simply give it a name, I'm saying I want the default thing.

And I could do this as well. It's just a longer way of writing the same thing.

If I want the default and some specific things, I can get the name I want to use for the default thing, comma, and then this list in curly braces of the name things that I want.

If I don't want anything that's exported but running the code in that module causes some side effect, I can do this, no access to anything.

Audience Member: You think you could find an awful lot of syntax for this?

Mark: Yes. Compared to Node.js, this is crazy.

23-More on Modules.png

There's a little bit more to this. You can say that "I want to pull in something from another module, but I'm not going to use it. But I want it exported for me so someone else who is importing me can use it." So I'm going to export everything from some other module, and I'm not even using it. The same thing here with pulling specific things.

Audience Member: Does that execute module-path with a side effect? What happened from there even if no one imports something from module path and a subsequent file?

Mark: Okay, I have to guess now. But I'm going to guess that the code doesn't run until someone actually imports it. That would be my guess, but I'm not sure.

And then, one last thing is that you can do conditional importing to complete this module loader API. So let's say I want to import this module, and then that returns a promise. If it's successful, then I'm given a reference to that module. It get's crazy after that. These conditional things that you can do.

Audience Member: You said you're not using modules?

Mark: We're not right now. I'm going to run out of time if I don't get going fast here.

24-Arrow functions.png

I really want to hit this one. Of all the features of ES6 this is the one that, for me, has made the biggest difference in my day-to-day coding is using arrow functions. It has really made a lot of our code shorter. Let me show some examples of that in just a bit.

But first, just for the syntax. The general syntax of an arrow function is you list your parameters inside parens, and then you have the arrow, and then a block of code. There's a lot of simplifications you can make. If you only have one parameter, you can drop these parens.  Interestingly, if you have zero parameters, you still have to have the parens. Okay?

Some people's reaction to this is: One,  just going to always use parens. But it seems that the reaction I'm seeing out on the web, so far, is that: that's not –. People really want this simple case of one parameter to be very clean, and they don't want to see the parens if there's only one parameter.

With the curly braces here, if you only have one expression, you don't need the curly braces. That works out really well if what you want is a function that returns a certain value because it automatically inserts a return for you. A good example of that is right here. This arrow function that takes a number and multiplies it by two. Well, that's the same as if I had a function that takes a parameter named x, and a curly braces, and inside I say, "Return x * 2." So, much shorter way to write that code.

One rule here is that you are not allowed to put a carriage return before the arrow. The parameters and the arrow must be on the same level. But you could put a carriage return after the arrow.

A couple of things going on here: You get what's called lexical this. Inside this block of code, the value of this is whatever it was outside that. It's not giving you a new value for this as it would if you used the keyword function there. That can be very handy in some settings.

You also get lexical super, and that comes into play when I talk about support for classes. We'll be getting to that in just a bit. But here's a basic example: I've got an array of numbers and I want to multiply all of them by two. So I do a map on that array — something from ES5 — and I get a new array with all those numbers doubled. But here, I'm defining a function that takes two numbers and returns the product of those numbers. And then I'm just testing it out. Using all of that, I can create an average function, I give it an array of numbers, and it's going to add all of those up using reduce with a very short arrow function that says "I'm going to add two numbers together and then I'm dividing by the link of that array to get the average." It works as you would expect.

Now why do I think this is a great use of an arrow function? This and this are suspect uses of an arrow function. And the reason is that: if you use an anonymous function, you don't see a name in a stack trace. That's going to happen to be here. If something goes wrong, I won't see a name for that thing in a stack trace. So for something like this, I think I would use the old style function.

Audience Member: A question about the lexical this. Does that mean that this is not just a new syntax for functions? It's more violently different. You take a working system and just convert the function in place of the syntax and you could very much break a working system.

Mark: For example, let's say you wanted to do a crazy thing like add a method to the string class. You would say String.prototype.foo =  and then you assign a function to it. If you use an arrow function there, that breaks; it's not right. If you want it to be a method, you can't give an arrow function.

Audience Member: It's not just a new syntax. It's a new kind of function.

Mark: Yes.

25-code.png

Before I move on to talking about classes, I want to show you the change that it has made in our code. Many of you are probably familiar with the UI-Router in Angular. One of the things you can do with UI-Router is set up resolve. Basically, I want to make a bunch of res calls before I go to this route. A common way of doing that is to create this JavaScript object, you give names to these things that you want to retrieve, and you'll end up making that data available to the controller. Then you can inject these names into your controller. Here I'm saying, "I'm depending on this thing called programSvc," and service here is going to be that programSvc. And I'm going to return the result of calling this. This actually is making a res call and returning a promise. I need to return a promise. And I'm doing the same kind of thing here.

Here we see the new code using arrow functions. This function that took a service becomes just that. I don't need the return keyword anymore. And because I have this one expression, I don't do the curly braces. And so all of this class is down to that. The same thing for the second one. That comma shouldn't be there. I really love this, the compactness of that.

One more example: When you design a custom filter in Angular, then you need a function that returns a function that implements your filter. Here's a simple custom filter that does absolute value on a number. I'm returning a function that takes a number and it just returns the absolute value of that. But with arrow functions, I can write it like this — which looks a bit confusing at first because there's two arrows in there. The way you look at this is that what I'm passing to filter as the second argument is a function that takes no arguments — that one. And that function returns a function that takes one argument that returns that.

Look at that a few times and I think you can get comfortable with this. A function that returns a function.

Audience Member: Does that mean that the arrow operator is right associative?

Mark: Yes.

Audience Member: Do you always do it this way?

Mark: Yes.

Audience Member: Well, that's also letting him use shorter names for his local names.

Mark: True. But I could do that this way.

I wasn't doing this at first. When I started switching these over to arrow functions, I realized that, "Oh, I could have done that."

26-Classes.png

All right. Let's look at how classes work in ES6. The key thing to remember about classes in ES6 is that it's really just "syntactic sugar" over the way you define classes currently. You have a constructor function — just an ordinary JavaScript function — and then you attach things to the prototype. That's what it's doing for you when it generates code from this.

Here I have a class called Shoe. You can have one function inside whose name is constructor. Input every parameters you want and then you're going to assign things to __this__ inside. Now, here I want to keep track of how many Shoe objects I create. You see down at the bottom here, I'm attaching a property to the Shoe class. In ES5, you would say I'm attaching a property to the constructor function. It starts out as zero. Every time I go into the constructor here, I'm bumping that up by one. You'd think of this as, like, class property.

These are the ways you define methods in ES6. Notice how I don't have the keyword function and I don't have an arrow function, either. You just have a name and things in parens. That's how I've noticed you're trying to define a method. And then just a code block. I'm going to say that two shoes are equal if they have the same brand and model and size. Then I have a toString and how I want out with this. I want to have a class-level method to build the ask "Have I created any shoes yet?" And here's the place where I can use an arrow function that doesn't take any parameters, and it's returning this Boolean value that counted the shoes greater than zero.

I'm going to create a bunch of Shoe objects in the normal way of creating objects in JavaScript. Then I can ask if I've created it, and it's going to say “true” because my count is 3 now. I can access the count, it's 3. I want to print out the second shoe, so it prints that out. Then I want to test if shoe 1 is the same as shoe 2 and it's not the same. But shoe 3 is the same as shoe 3. That's a quick example of implementing a class with ES6.

The next thing we want to look at is how could I make the class that inherits from this one?

27-...Classes.png

There's a lot of messy steps that you have to do in ES5 to correctly set up inheritance between classes. Three things you have to do. If I think really hard I can remember two of them, and then I go back and look at the course notes and then remember what that third one was. But now you don't have to worry about that. You just say, "My class RunningShoe extends Shoe." Yey. That's the same syntax as you have in Java.

Here the super keyword is going to come into play. To constructor RunningShoe: "I need the same things I needed for Shoe — a brand, a model and a size; but I also want a type of of a running shoe." And then I'm calling the superclass constructor, passing it the things that it wants, holding on to type. And then I'm going to initialize miles to 0. That's how many miles you run in these shoes.

It's a general idea in running that you should replace your shoes every 500 miles, or you'll start to get a knee injury. That's what I'm going to do here. I'm going to fill the "ask any running shoe" if it is time to replace it; and if it is, if the miles are greater than or equal to 500. And then I can add miles to the shoe. Up here I'm constructing a RunningShoe and passing it all the things that it needs. And I add 400 miles to that shoe and ask if I should replace it. It's not ready yet. Then I add 200 more miles and ask him. Yes, now it is ready to replace the shoe. Very easy to inherit from another class.

28-Enhanced Obj Literals.png

Enhanced object literals. The cool thing here is that: before ES6, whenever you would make a literal JavaScript object, you always had clutches of key value pairs. But now you can have just a key, or is it just a value. You can't really tell. Look at this object. I have these local variables: fruit set to apple, number set to 19. I'm going to construct an object that has this one key value pair foo and bar. But what about these? Just fruit and just number. Whenever it sees that, it says, "Well, let me see if you defined that. If you have, I'm going to create a property named fruit that in this case, that's the value apple. And get property number, the value 19." So less to type.

The assumption is that you had to have that value for some other use. And now you want to add it into an object.

Audience Member: I don't know how much this would be helpful in the future, but just a very simple example of making Angular code more efficient. This would allow you to bind to the individual — like, you will have both sets of variables here: the fruit and the number, and then the full object. So the object will be like a meta set of data about your entire app — running data of your application. But you only look to bind into it apple and number. That's why you don't have to go digging through the entire object data structure.

Audience Member: I'm assuming references like fruit in the object is not a reference back to the original fruit variable, is it?

Audience Member: That's a good question.

Audience Member: Probably not.

Audience Member: I'm assuming that it's created a key called fruit and a static scalar value that has the value of apple. It's not, somehow, a reference back to the original fruit variable.

Audience Member: Yes, probably not.

29-...Enhanced Obj Literals.png

Mark: Another cool thing you can do is give keys to an object that have a computed value. Before ES6, this is the way you would do it. I can create an empty object, and then I want to add property to it whose name is in this variable. Or there's some expression that gives me the name, and then I can add that property. But in ES6, I can put square brackets around an expression that is the key. It will compute the value and then that becomes the key.

If I want to add a property to an object that the value was a function, the old way of doing it would be like this: I got a name and a colon and then just a regular function. But the new way is: get the name and then the list of parameters. This is the same thing that we saw back when I was defining a class, the way I defined the equals and the toString methods.

Audience Member: Does an arrow function work there, as well?

Mark: No. The problem is the lexical this thing. Yes, and I'm going to show that right here.

30-Property method assignmt.png

If you're wanting to add things that are truly methods of an n object, then here — doing it the old way — in this object I have the number property, and then I want to have this way that I can multiply any number by that one. So I could pass in a 3, I'd expect to get back 6. The old way is to just use a function like that, and when I refer to this inside, it's referring to that object. The new way is: I write it the same way you saw in the constructor and I still can use this. If I try to write product, and I try to use this here, what is the value of this? If the value of this that existed out here, and then that's wrong. So the key thing to remember is: Don't use arrow functions for methods. Instead, use these new syntax.

Audience Member: So that syntax you've got there actually works, will just work as expected.

Mark: Exactly. it's not a syntax error. Well, so this isn't a new thing, right? You're used to sometimes not understanding what the value of this would be.

Audience Member: I'm anticipating the wat 2.0 talk.

Mark: Okay. I wasn't planning on going into detail on the rest of the things here. But I certainly could do a follow-up talk at some point, if you want to.

31-New Math Methods.png

32-New NUmber Methods.png

33-New String Methods.png

But I just want to point out there's a lot of new methods added to Math, a lot of new Number things, new String methods. I have started using some of these. Now you don't have to be a regular expression expert with every single thing you want to do. You can just say startsWith and not have to remember "slash, char, some value, slash". And endsWith and contains. We are using those in our code now.

34-New Array.png

Some new Array things.

35-Template Strings.png

Template strings. A new kind of strings surrounded by backticks. There are dollar phrases and expressions inside. Different way that you might start doing console.log. It's even more advanced than that when you get into these tagged template strings. That's too much to talk about now.

36-Default parameters.png

Default parameters. Here I have this makeDate function and I can pass in a day, a month and a year. But if you don't give me a month and a year, I default them to the current month and a year. A funny thing about this ability to have default parameters is that it means that there's a tricky way that you can say now that a parameter is required. Look at this: I have this req function that every time you call it, it throws an error saying "missing argument". You just set that as the default value of the parameter and if they don't supply it, it's going to give you that error.

37-Rest parameters.png

Rest parameters. This report function takes the firstName, the lastName. If there's any more things passed to it, they'll be collected up in this variable colors, which will be a real array. For now, you would use arguments to get to that, but arguments isn't a real array and so you do the array slice thing to turn it into an array. You don't have to do that anymore.

Audience Member: Does the dot-dot-dot have a name yet? It doesn't in PERL. It's called the yada-yada-yada.

Mark: Well, the problem here is that the dot-dot-dot in ES6 is used for two different things. It's used for: here it's called the rest parameter and the other use, it's called spread. That's where you have an array and you want to explode it out into its separate elements; so there, it's called spread.

38-Spread Operator.png

Here's the example of spread. I want to push some things onto arrays. And this push method, you can't pass it in an array. Well, you can, but it will be pushed on as a whole array instead of the individual elements. Here I can say, "Take this array and explode it into the individual elements." And those get passed to push as separate arguments.

39-Destructuring.png

Destructuring. I've got my variables a, b and c and I want to swap them all around. I can say, "Take all these values and assign them to here in that order." No need for temporary variables.

Audience Member: Is the var there intentional? The second –

Mark: Oh, that's a good question. Yes, maybe I don't need that. Send me a note about that —  slide 40,  do I need that var?

A more common use of destructuring is something like you're seeing here. I have this deeply nested array, and I'd like to pluck out certain values from that. Again, maybe I don't need that var. But taking that array and assigning it over here so a is going to get 1, b is going to get 3. Notice how I don't have anything in front of  the comma; that means I don't care about this value. And it just continues on like that. It's very easy to pluck things out of an array.

Also, an object. So you have there an object with color and weight and size properties. And I'd like to extract out of that just the color and the size. That destructuring does that for me. You can do this with parameters to a function. I'm using destructuring as my second parameter here. You're expected to pass, as the second parameter, an object that has at least these properties. You can have any other properties in addition to this. But I'm pulling this out and all those can tumble into variables inside the function.

Audience Member: If they don't have those properties, just set to undefined or does it throw an error?

Mark: I'm set to guessing again. I'm going to guess they're undefined.

Audience Member: I have a question, I think it applies to this slide and the last few. It seems like some of the first few things you showed us were kind of like important new language capabilities that will kind of make the ecosystem consolidate. But it also seems like it's a lot of just grab bag of just various bits than improvements. Which one of those are you using at work?

Mark: I was going to list what are we actually using in our code right now. I've just said earlier the big thing is the arrow functions. Next, I'm using the enhanced object literals a fair amount. Just yesterday, for the first time, I used a new Set class. I haven't gotten to that yet. There is now a Set and a Map class. Sets are obviously a collection of unique things. There's a method on a Set that you can ask "Is this thing in the Set?" That was exactly what I needed.

Map. We've been living without maps for a long time and just using JavaScript objects. With the limitation of the JavaScript object, which is the keys have to be strings, but in a Map the keys can be anything. They can be numbers, they can be other objects, they can be arrays. We have that now and Traceur supports both of those. There are also going to be WeakSets and WeakMaps that have an effect on garbage collection. I'm not sure that Traceur fully supports those as yet, but it's certainly coming. But you're right, there's a mixture here of big ideas like modules and classes and then these little things like default parameters. Most of these, I'd say, that I like. Most of them have gotten very popular in other languages like Groovy.

40-...Destructuring.png

Here's another really good use for destructuring. I have this String, and I want to use a regular expression to pull some data out of that. My regular expression has some groups in it, so I can pull out the pieces of this date and I can get to the month and the day and the year. Then I run exact on the regular expression and pass it the date string. What it gives me back is an array where the first thing is the whole match, and then the rest of the things in that array are the parenthesized groups that it matched against. That was all I wanted. So I can say, "Use destructuring, and I don't care about the first thing, and grab the month and the day and the year." That's a very compact way of getting pieces out of a regular expression.

Anytime you're passing in some kind of a configuration object into a function, that's another good use for destructuring. Here I'm saying the configurations that I handle are those four. Pass me an object with anything in it and I've got those, I don't have to pull them out once I get inside. Here's an example of calling it.

41-Collections.png

Okay. Here it says "Collections: Set, Map, WeakMap, WeakSet". I think I don't have time to walk through that. But your guess as to what it would be like to work with a Set or a Map is correct, I'm sure.

Audience Member: Is there anything that's deeply important about those ES6 features vs. just a library that has a Set and a Map? Like, these are special syntax?

Mark: No, just a library. Which is why 6to5 isn't giving you that, and Traceur is because they have a runtime.

Audience Member: Yes, but why do we need a new version of a language to get a Set and a Map class?

Mark: We don't. But I think that maybe they decided that it was a good idea if everybody used the same Set class vs. picking different libraries. That was fundamental enough for it to be just one.

Other things that I don't have time to talk about: Proxy objects; Promises — a standard promise library for JavaScript; for-of Loops — it's a different way of iterating foo things. Arrays are one kind of thing you can iterate through. But also, there's more general concept of an iterator which becomes very important when combined together with generators. I've got a lot that I could talk about: What it's like to work with iterators and generators; what generators do for your use of async codes so that your code can look more synchronous style even though it's asynchronous.

The next improvement over that is to look at features in ES7. I really love async and await.

Audience Member: Are you using those?

Mark: We are not using it yet. But we probably should start using it soon. But it's such a new thing. Anybody who looks at code that uses this is going to be immediately confused. We need to have a really good explanation of how this works. But I do have an example here. I'm excited about that.

Type annotations are part of ES7. You're hearing lots about this now with AtScript and TypeScript and — what's the latest one? — Flow one. One way or another this, maybe, is going to be a standard thing in JavaScript.

42-Summary.png

I wish I had another hour to talk about this, but I think we hit the high points. At least, for me, it has been great to start using some of these features in my Angular code now.

Audience Member: I saw one feature you've started using in Angular. But this one I want to know if you can use it in Angular is — the Angular people, it turns out that they actually think in my Java class or in the languages, and so for Angular 2.0, things we thought of as "Oh, that's just for function", they already thought of them as a class. And they're going to be a class. Question is: Can I type "class something" and might make my controller with the class syntax, and have useful things happen?

Mark: Going along with that, they've perceived the class with an annotation. The annotation, it very much looks like Java. I've been searching around trying to find out where did this syntax come from? Is this something common in ES7, ES8? Maybe my Googling failed me, but I'm not finding it. So I'm thinking that their notion of annotation is something that they invented.

Audience Member: Yes, it's like Java annotation, probably written in JavaScript. Even aside from the annotation part, can you use the class syntax to make your controllers?

Audience Member: I'm pretty sure you can with controllers.

Audience Member: Are you using the class?

Mark: Oh, definitely not.

Audience Member: So you're sort of using the language enhancements but you're — so far — dodging these, particularly Angular way.

Mark: Exactly.

Audience Member: When I started digging into this, I actually compared your demo to several others. That was one of the defining distinctions. It's that a lot of people, they want to dive off the deep end and anywhere that you could assign a class, that's what they did. For some reason, they've equated ES6 to classes. And even though there's nothing really different there except for the syntax of how you declare the classes, they've started doing that in Angular. Because that controller actually accepts a class as well as a function, they've started replacing that function with a class.

Audience Member: But does it work?

Audience Member: Yes, it did work. I've experimented with it, as well. It's just that there's no reason to. I think that they're migrating towards that.

Audience Member: Yes, you're getting ready for the future. If you're going to be in Angular two years from now, I think it's going to be all classes everywhere. And they're going to have Java-style  annotations on it everywhere, but we can't solve that one yet. But I'm wondering if we could take a step forward.

Audience Member: I'm really not sure enough about what the eventual Angular syntax will look like. Even if it does use classes, to feel confident that if I go class-crazy in my code today, that it will be Angular –

Audience Member: – They might be the wrong classes.

Audience Member: Yes, that's the thing. I feel like I may have just made additional work for myself to Angularize my now class-based code.

Audience Member: Well, even with things that we can't be sure of — like the name of directives being moved to the forefront, they're getting away with how our directives should work.

Audience Member: I really think our approach going forward is to move forward on ES6-style  JavaScript code, but to try and make as much of our JavaScript applications with an Angular layer, as opposed to Angularize the applications all the way to the bottom. That we keep the Angular stuff fairly — not completely separate — but identifiable as like "This is the Angular piece and everything else is just more pure JavaScript."

Audience Member: Have you been taking steps in that direction?

Mark: I'm not explicitly trying to move toward Angular 2.

Audience Member: I mean in the direction of trying to write more of your application as a  JavaScript ES6 application kind of wired to Angular vs. sort of pervasive Angular-everywhere style.

Mark: No, I think we're trying to separate the Angular parts from our non-Angular parts.

Audience Member: In your Traceur demo, instead of using a service to move your business logic, you actually put all that in a module, imported that module and used that inside your controller, instead of using a service or a factory. And I thought that was an interesting take.

Mark: Yes. I did that in a demo. But I haven't done that in our app. I guess I'm taking a cautious approach to this because our app is in production.

Audience Member: There's an argument that Angular service and factory don't really do much. That maybe you should just not use them, and use ES6 modules and classes for what you would use services and factories for. And then only use Angular for the visible user interface stuff for doing things.

Audience Member: Well, if you didn't want to take advantage of that — your factories and services — you could still build all of the content of those things as ES6 modules, and simply use them with service or a factory wrapper.

Audience Member: Yes, but if you have export and import and all that, why not just use those to get your dependencies?

Audience: Then you can wrap in resolve in the end.

Audience Member: Yes. Okay.

Audience Member: And you also get all the supposed advantages of dependency injection. That's a good question for you. If I wanted to get some of the same flexibility for testing — like I've got my really destructive HTTP module in ES6 and I want to use that in my test environments where I want mocking, with ES6 features do I have all of the mock ability and replaceability that I would have with Angular's dependency injection? Just using ES6 features?

Mark: I think a part of that answer is to look into ES6 proxies.

Audience Member: Okay. You see what I'm getting at, though? I'm trying to think of what the advantages are that we'd get from using these services and factories. And if we can get more of that stuff out of the native language itself, then, sure, let's not continue to use this in Angular. In fact, I think the Angular team itself would say, "The reason that we put all these tombstones up on slides is because, now, we don't have to do this stuff. We can leverage ES6 and beyond to do it for us." So maybe we need to be doing the same thing.

Audience Member: That's what I was thinking. I guess what I'm getting at is, if there are features that you can get out of ES6 today that make you not use certain Angular features, then that makes you less impacted by the Angular changes.

Mark: Yes, I agree with that.

Audience Member: Can you say you're slowly or you, guys, are taking it slow in that direction? If you already have major application productions, you don't just want to go rapidly changing.

Mark: Right. We're adding one feature at a time. First thing is just to introduce arrow functions. And then we started doing the enhanced object literals and then the Set.  Just yesterday, I've used the Set for the first time.

Mark: I don't think I would be happy doing this if I wasn't also using Gulp or Grunt. We're actually using Gulp right now. It's very important to me that this happens automatically.

Audience Member: Some IDEs will do it for you, too.

Mark: All right?

Audience Member: Summary recommendation: Should we all be picking up ES6? Is there any reason to wait?

Mark: I don't think that there's any reason to wait. The only caveat is what browsers you need to support. And if you need to support much older browsers, then that's the reason to use 6to5 instead of Traceur. But other than that, I don't see a reason to wait.

Audience Member: You wouldn't give up, you'd go ahead and use 6to5?

Mark: Yes.

Audience Member: Okay. Thank you.

Audience Member: Is it really safe? Like, ES6 is a superset of ES5. So you need ES5 support. If I don't have that?

Mark: You can use shims. We had no trouble using 6to5 in IE8.

Audience Member: Can I take the JavaScript files that I already have? Can I start running them through Traceur? And will it be 100 percent successful or will it be almost successful?

Mark: We have not found any problems with transpiling our code that uses no ES6 features.

Audience Member: Okay.

Audience Member: The same code has the same bean.

Mark: Right.

Audience Member: What do you think your next, big, like,  "I'm going to adopt?" Is there a next big feature that you're really thinking –

Mark: – I'd say it will be modules.

Moderator: Can we give him some applause?

Audience Member: You saved us all, Mark. You saved us all.

[a]haven't ?

[b]Yes. haven't. I added it in. Thanks.

Published by

Kyle Cordes

The technical principal of Oasis Digital, Kyle Cordes drives our technology and architecture choices. Kyle gives presentations and talks at user groups and other events.