Better JavaScript Using Modern Techniques

I’m going to highlight some of my favorite modern JavaScript features in this post. Most of these are new to ES6, but a few of them are not. I call these features modern because they allow JavaScript to be written in a way that supports conciseness for better readability. This isn’t intended to summarize all of ES6. It’s mostly just tips for more readable and interactive code.

Some parts of this post use features that might not be in modern browsers or even in the latest versions of Node.js. You might have to use a transpiler like Babel.

let & const

The var keyword has been the defacto way to create variables in the past, but two new keywords, let and const, have been introduced. The let keyword will replace many of your var declarations.

It works very similar to var, but instead of providing functional scope to your variable like var, it provides block scope. Block scope (let) has been typically used in many popular programming languages, such as C#, Java, and C++. When using let (block scope) the variable you define cannot be seen outside of the pair of curly braces in which you define it. This is in contrast to var (functional scope) where the variable can be used anywhere within the function, even if it is declared inside of nested braces. Here’s an example of how let has block scope and doesn’t allow you to see the variable outside of that block.

If these variables that were declared using let were changed to use var then this script would work fine and there would be no reference error thrown. Since var uses function scope, the declaration pulls (hoists) the var instantiation to the top of the function (in this case the window or top of the script) and removed it from the curly braces. But because we use let, the only place that name2 can be used is inside of the curly braces of the if statement.

const is a new keyword that also creates a variable, but it doesn’t allow the variables value to be changed. const variables have block scope, just like let.

Better functional expressions

Functional expressions are functions that are read a runtime. ES6 allows you to create functional expressions using the fat arrow operator. It allows for very concise function declarations that are easy to read. It also makes the scope inside the function the same as the scope that encompasses it. Because of this we no longer have to set something like var that = this whenever we use a functional expression.

There is an even shorter syntax for one-liners where you can leave out the curly braces.

Easier looping

If you’re going to use an anonymous function to loop through an array then the fat-arrow can help you make them very readable.

Notice how there is no function keyword being used or any curly braces. Just some very readable text. This is very helpful for one-liners.

You might also be familiar with the for of loop that is common in many languages including JavaScript.

JavaScript supports array comprehension, which allows you to dynamically process an array into another array. If you work in Python, this should be very familiar to you. At the time of this writing Node.js does not support array comprehension yet, so you’ll need to use a transpiler for this.

You can easily loop through an object and it’s keys.

The good thing about using Object.keys() over other possible alternatives is that it only provides enumerable properties, so you don’t need to worry about calling {}.hasOwnProperty() on the object before you access it. If you actually want the non-enumerable properties, such as ones from the objects prototype, then you might want to just use a regular for loop.

Fat-arrow functions can help to test arrays for specific conditions in a concise way.

We can easily get the index of an array element.

We can also easily create new arrays based on existing ones.

You can get rid of elements from one array when creating a new one.

You can turn your array into a group of variables using something called destructuring. Node.js doesn’t currently support this by default, so you’ll need to either compile with specific flags enabled or use transpiling.

Using destructuring you can easily swap different variables. I’m not sure what the performance implications of this will be once V8 and the other JavaScript engines implement it, but I’m guessing that it will be optimized to where it won’t be an issue if you create the array during the process.

String templating

You can create strings with variables much easier in ES6 (make sure to take notice that string templating uses the back tick character and not a single quote).

Function argument upgrades

You can now provide default values for function arguments.

You can capture any number of arguments sent to a function as an array using the spread operator. All arguments sent to the function will be placed into an array in the order that they were sent.

Object getters, setters and property definitions

You can easily create getters and setters for objects instead of directly accessing a property.

You can also define object properties using the defineProperty function. Defining it this way allows you to control how JavaScript allows a user to manipulate the property. You can make it writeable, enumerable and/or configurable. If you set the writeable property to false, then we can not change the value of the variable later.

You can also use defineProperty to create a getter and setter for the variable.

Multiple properties can be defined at once by providing an object as the second argument instead of the property name.

Hiding data with closures

Closures can help keep data private by internally holding references to outside data.

Notice how the yell method uses the yellLength variable. Even after being returned from the makePerson function it still holds a reference to the yellLength variable. The yellLength variable is not being passed into the function when it is called, it is just holding on to the reference from when the yell() function was declared inside of makePerson(). The holding of the reference is created by the closure. We aren’t able to alter the yellLength variable, making closures great for hiding data and creating private variables.

Easier object configuration

Creating objects with configuration objects can be a chore when you need to specifically add each individual property. You can use Object.assign() to make it a much easier process. It will take the properties from one object and inject them into another.

Classes

ES6 now includes support for the class keyword. This makes it easy to define classes that will build your objects. It’s important to note that under the hood the new class system works using the prototypical inheritance system that JavaScript is based on. The class keyword is just syntactic sugar on top of it.

Even with the implementation of the class keyword you will most likely still find yourself defining objects using typical object composition that has been the staple of JavaScript for many years. Classical inheritance has it’s place, but object composition does as well, especially in JavaScript. If you have very long inheritance chains that are hard to follow, you may find the falling back to object composition is a better choice for that part of your application.

Separating logic with modules

Modules are pieces of code that are contained from other parts of your application. You export a module so that it can be imported by other modules or parts of your application. If you don’t export a module it is essentially private. Any JavaScript file (.js) can become a module.

By using the keyword export you are allowing other modules to import this module.

When importing, you leave off the .js extension of the module name. You can provide a file path if you want to import modules from other directories.

If you don’t like the name of the property name that the module exported you can change it when you import.

You would now  reference the property by using myModule instead of testModule. You can export multiple properties at the same time and also change the name of the exported property. You can also import multiple properties from the same module at the same time.

You can export properties from a module at any time. Some people like to put all exports at the bottom of the module while others will place them at the top. The export keyword is read at compile time so it does not matter. You can import all properties from a module as a single object.

Promises

Promises are objects that help to organize asynchronous code and callbacks. They help to organize the sequence of your code, which will make it more readable. So instead of having a bunch of async callbacks that are nested 10 tabs deep, you will be able to chain methods like you would with normal objects. When creating a promise, it takes a single argument, which is a function that accepts a single argument called resolve. When the resolve function is called it signals the completion of the promise/request.

The key is making sure that the resolve object is called. So in this example, we need to make sure that the $.post function is calling the resolve function once it is complete. When that happens the promise is complete at then the next .then() function is called.

Leave a Reply

Your email address will not be published. Required fields are marked *