I began learning JavaScript using the ES5 version to understand the fundamentals of the language. Once I got my feet wet with ES5, I was introduced to ES6. There were so many updates that I became too anxious to fully immerse myself into another level of JavaScript until recently. This will be part 1 of my learning journey of ES6. In this post, we’ll review Promises, destructuring, Modules, transpiling, and the spread and rest operators.
Starting with Modules.
Modules are collections of small independent units known as components. Components can be described as “everything that can be exported by the export
statement that can be reused in our application” by Dler Ari in A Practical Guide to ES6 modules. These modules improve scalability which is the ability to adapt to large amounts of data without compromising performance and efficiency. By “encapsulating behavior”, debugging becomes easier to pinpoint. Modules allow a separation of concerns and give you the ability to import and export only the necessary modules for your functionality which keeps your code DRY (Don’t Repeat Yourself).
Next: Spread and Rest Operators.
Differentiating the two operators can be difficult considering they have identical syntax: ...value
. The difference can be seen by examining the logic using the operator. Despite looking the same, the spread operator and rest operator are opposites of each other. The spread operator expands iterable values into a collection and the rest operator condenses the remaining values into a collection. On top of that, you can do a multitude of things with the spread operator; you can split strings into an array, copy values from collections into other collections, and pass function arguments. For the rest operator, you can reduce values into a condensed collection.
Moving on to destructuring.
To destructure is to extract values from arrays, and properties from objects, and store them in a variable. There are many uses for destructuring, such as swapping values or used as function parameters, but the main object of destructuring is accessing certain values in collections. Let’s start with the syntax for destructuring
At first glance, it appears to be the inverse operation for variable assignment which is close to what destructuring does behind the scenes. Depending on the collection you are destructuring, your variables will directly correspond with the collection’s values. If you are extracting from an array, the order of the variables will affect what element will be assigned to it; the first variable will be the value at the 0th index, the second variable will point to the 1st index, etc. When extracting from an object, the variable name will have to match the property’s key that you are targeting. Thankfully there’s a workaround for each of these issues.
The comma separator allows you to skip elements when destructing arrays. Keep the space empty between the commas to determine the element you want to skip over.
const campers = ['Lazlo', 'Clam', 'Raj', 'Lumpus']
const [duckDuck,,, goose] = campers;
console.log(goose); // Lumpus
If you wanted to assign a new variable to an object’s property but didn’t want it to have the same name as the property’s key, you could do just that.
const myCar = {
color: 'red',
year: 2004,
hasGas: false
}
const { color : jetta } = myCar;
console.log(jetta); // red
You can also incorporate the rest operator in destructuring to stash leftover values.
const family = {
daughter: 'Peppa',
mother: 'Mummy Pig',
father: 'Daddy Pig'
};
const { daughter, ...parents} = family;
console.log(parents); // {mother: 'Mummy Pig', father: 'Daddy Pig'}
Now let’s look at transpiling.
Aakarshit Giri said in his JavaScript Transpiler article, transpilers (aka transformation compilers) “convert code written in one programming language into another programming language while preserving the original functionality”. In other words, taking out ES6 code + converting it into ES6 so it can be read by all browsers/networks. Popular transpilers include Babel and Webpack. In this post, we’ll focus on Babel.
Babel transpiles versions of Javascript, mainly from ES6 into “backward compatible” versions suitable for browsers/environments. Made from plugins, Babel targets certain syntax and refactors the code to fit the desired version. For example, the @babel/plugin-transform-arrow-functions
plugin targets arrow functions and transforms them into function expressions/definitions with the function
keyword and maintains functionality. With that being said, you run the risk of having larger, less efficient code. However, that does not hinder your ability to write cleaner code.
And finally, we’re on to Promises.
MDN defines promises as an object that represents the eventual completion or failure of an asynchronous operation and its resulting value. GeeksforGeeks likens promises to a receipt being that the receipt is a promise that you will receive your order and is a placeholder for your purchase. These promises came about as a means to avoid callback hell, which is excessive nesting of callback functions that increases the complexity of the code you’re writing and also makes it difficult to read and execute. Promises have a task that will be checked for success or failure and instructions on what to do depending on the execution of the task.
From reading that, one would infer that the instructions for the result of the operation would be callback functions and they are! Except they aren’t passed into functions, instead they are attached to the promise, like methods (which is what they are).
The callbacks you’ll chain to promises will either be .then()
or .catch()
. The then
method handles both success and error callbacks and catch
is used for error handling. You can use the then
method for only telling the program what to do if the operation is completed because the second parameter is reserved for an optional error callback. But if all of your error handling for every step in the chain is the same, you can use catch
at the end of the chain.
const myPromise = new Promise((resolve, reject) => {
let a = false;
setTimeout(() => {
return (a) ? resolve('a is found!'): reject('sorry, no a');
}, 300);
});
myPromise
.then(value => { console.log(value) })
.catch(err => { console.log(err) });
// 'sorry, no a'
In this example from Kingsley Ubah in his post about Promises, he provides a great example of what a promise chain looks like and its behavior. The code shows what the outcomes will be once the Promise is settled. Since myPromise
rejects or fails, we know that the error will be logged to the console. A question that may come to mind is 'how do we reach the catch method?' and the answer to that is the then
method will return a Promise regardless of its completion or failure. If we do not return a Promise, we won't be able to determine its status of completion, and that will lead to a multitude of errors.
These new features make accessing values more flexible, code more readable, and averts errors. This concludes part one of my deep dive into ES6 features. In my next post, I will go over generators, iterators, proxies, and reflections.
Top comments (0)