ES6 JavaScript introduced some of the most groundbreaking features that engineers use in their code every day. From the introduction of the const and let keywords, to spread and rest syntax to ES6 modules, and everything in between, this powerful update has revolutionized the way in which engineers write clean, efficient, and maintainable code. We encourage you to try them out for yourself and check out the Codesmith blog for articles that dive deeper into these ES6 features.
We at Codesmith cultivate technologists who are at the intersection of society and tech, able to meet this moment and thrive in an ever-changing world. Ready to become a modern software engineer?
ECMAScript is a standard that defines scripting languages like JavaScript. Managed by ECMA International, it serves as the blueprint for various scripting languages such as JScript and ActionScript, but JavaScript is the most widely adopted implementation of ECMAScript.
ECMAScript releases periodic updates to make scripting languages more efficient and user-friendly. Let’s dive into JavaScript ES6 (also known as ECMAScript 2015), one of the most important versions, and explore the key features it introduced.
JavaScript ES6, or ECMAScript 2015, was a major update that revolutionized JavaScript by improving readability and efficiency. Before ES6, JavaScript was less effective in handling large-scale applications. ES6 introduced new syntax and features that made JavaScript cleaner and more powerful.
In ES6, let and const replace var for variable declarations. Let provides block scoping, which means variables declared with let are only accessible within the code block they are defined. Var, on the other hand, is function-scoped and can cause issues with accidental variable reuse.
Take a look below to see an example.
Below, let’s block scope allows us to declare the variable codeSmith which will only be accessible within the code block between lines 22-25 and is not tied to the codeSmith variable declared on line 20.
If we were to execute the code above using var instead of let, our code would reassign the value of codeSmith on line 23.
Similar to var, variables declared using let are mutable. This means that if you initially assign a value to a let variable, you can reassign (change) that value later on with no issue.
Let’s say you have a function that keeps track of log in attempts. You initialize a variable let loginAttempts = 0. Each time a user tries to log in unsuccessfully, you want to increment loginAttempts so that, once it hits 3, the user needs to wait one hour before attempting to log in again.
Often, we want our variables’ values to be immutable, meaning that they cannot be reassigned. This is where the const keyword comes in.
Const ensures a variable cannot be reassigned after initialization, although objects and arrays can still be mutated. This is particularly useful for ensuring immutability within your code.
Just like let, the const keyword is block scoped. Below, a variable is declared using const on line 20. Within the code block between lines 23 and 26, a variable with the same label of codeSmith is declared but only accessible within that code block.
It’s important to note that, while variables declared with const cannot be reassigned, their values can still be mutated if they reference an object (including arrays). For example, suppose Jane owns a house (represented by an object). She can repaint the walls or renovate rooms (mutating the object’s properties), but she cannot sell her current house and buy a completely new one (reassigning the variable to a different object).
Below, the value of the first element “array” can be reassigned as arrays are mutable. However, trying to reassign “array” to a completely new array (or any other value) will throw an error.
Arrow functions simplify the syntax for writing function expressions. They are especially useful for small functions and improve code readability. The syntax is shorter compared to traditional function expressions:
A function declaration is when a function is defined without being assigned to a variable.
A function expression is when a function is assigned to a variable.
In JavaScript ES6, arrow functions allow for shorter, and oftentimes, more readable syntax for writing function expressions.
In the example above:
Arrow functions are good to use when you have to write a simple function like the one in the example above and do not necessarily need a function body. They are also useful within higher order functions (map, filter, reduce, etc.).
Arrow functions should not be used when you need your function to be bound to its own this object or when defining constructor functions. Check out this article to learn more about JavaScript Arrow functions.
Template literals make string interpolation and multi-line strings much easier than traditional string concatenation.
Template literals are an incredibly useful feature introduced by JavaScript ES6 and you’re going to find yourself using them quite a lot throughout your career. Before their introduction in 2015, strings had to be concatenated in the following way:
The example above works fine, but if you’re concatenating long strings, this can take quite a bit of time and become pretty tedious. This is remedied using a template literal. In the example below:
Template literals can also be used for expression embedding as seen below.
It’s important to also note that template literals preserve line breaks allowing you to create strings that span multiple lines without having to use ‘/n’.
Destructuring allows for easy extraction of values from objects or arrays and assigning them to variables in a cleaner, more readable way.
If you’re new to ES6, destructuring may feel a bit difficult to wrap your head around because the syntax is different from traditional variable assignments but, with a little practice, it will start to feel intuitive. Destructuring allows you to access properties within an object and assign them to a variable at the same time.
Multiple properties can be accessed within the object at the same time. Note that the order of the keys does not matter, but the variable being initialized must have the same name as the corresponding property key in the object (exObject). For example, below,
const { doggies } = exObj would log ‘undefined’.
Destructuring can be used for arrays as well. In the example below, the variable dog will have the value of the element with the matching index in exArray (0 in this case).
Similar to object destructuring, multiple elements can be accessed at the same time.
You can also skip elements in the array by leaving gaps.
For a more detailed breakdown of destructuring in JavaScript, check out this article.
The spread operator is used to take the elements of an array or object and spread them out into individual items.
Below, we see an example of the spread operator being used to spread the properties in obj to be combined with newObj resulting in an object with four properties.
This JavaScript ES6 feature is also an excellent way to concatenate two arrays. Below, the spread operator spreads the elements within array out into individual elements within newArray resulting in one large array with all five elements.
In the example above, the spread operator creates a shallow copy of exArray and pastes the elements into newArray. Below, we see what would happen if we did not use the spread operator.
If you're still unsure about these concepts, don't worry! With more experience, you'll get comfortable with the difference between primitive types (like strings and numbers, which are copied by value) and composite types (like arrays and objects, which are copied by reference). Understanding how value and reference assignments work will make these ideas clearer over time but, for our purposes today, just know that the spread operator allows you to take the elements/properties of an array/object and spread them out into individual items.
It can be difficult to differentiate between the rest parameter and spread operator as they use the exact same syntax (...). You can think of the rest parameter as doing the opposite of the spread operator. While the spread operator will spread the elements of an object or array into individual items, the rest parameter will take multiple individual elements and combine them into an array. In the example below, num1 will pair with 1, num 2 will pair with 2 and nums will pair with the rest of the inputs.
This JavaScript ES6 feature is particularly useful when defining a function that may take an unknown number of arguments. The rest parameter creates an iterable array containing all of the remaining arguments after the named arguments have been assigned. Below is a simple example of how an unknown number of inputs can be operated on within a function using the rest parameter to transform those inputs into an array.
For more information on the spread operator and rest parameters, be sure to check out Codesmith’s blog on the subjects.
Another major feature added to JavaScript by ES6 is classes. Before ES6, inheritance was handled by manually manipulating objects’ prototypal chains to share methods and properties. For example:
Above, each new instance of the Animal constructor function will have its own unique species property (seen on line 124). Because the speak method has been placed in the Animal prototype, each new instance of Animal (dog and monkey) will have access to it as we see on lines 126 and 127.
This syntax can take a while to understand and is considered to be a bit antiquated today. Below we see an example of what is often referred to as “syntactic sugar”. Everything is still happening the same under the hood, but ES6 classes provide a more concise syntax for implementing inheritance.
In the example above:
With ES6 classes, unique data (like this.species) goes directly on the constructor while the functionality that we want each instance to have access to (like the speak method) belongs on the prototype.
Prototypal inheritance and ES6 classes are incredibly powerful. It can take a little bit of time to get the hang of it but, luckily, Codesmith offers some fantastic resources on the subjects. Be sure to take a look at their “Hard Parts” lecture and CSX unit on “Prototypal Inheritance and ES6 Classes”.
JavaScript’s ES6 Promises were introduced to provide a simple, uniformed way of handling asynchronous code. Before ES6, asynchronous operations were primarily handled using callbacks and third party libraries.
With the Promise Object, engineers have complete agency over the asynchronous code they want to write in a standardized, straight forward syntax. This has improved readability, allowed for the chaining of asynchronous functions, and made error handling a lot easier.
A Promise is an object that represents a value that may not be available right away but will be resolved eventually. The Promise Object:
In the example above:
Promises are fundamental to modern JavaScript asynchronous programming but they can take time to get comfortable with so don’t stress if this feels a bit confusing. With some practice, you’ll be using Promises in no time, we promise! Check out this article for a deeper dive on JavaScript Promises.
Default parameters are a small, yet incredibly useful change in ES6 that simplify your code and help with error prevention. Instead of having to write extra code to set default values when an argument is missing, like this:
ES6 lets us define default values directly in the function declaration! Like this:
In the example above, the default value of ‘Friend’ is used when the function is called with a missing argument. When called again with ‘Sam’ passed in, the default of ‘Friend’ is overwritten by ‘Sam’.
Default parameters even allow us to use expressions, and reference other parameters, like this:
In this example:
By now, you’ve probably used a general for loop to iterate over a string or array and access each character or element by its index. A for…of loop iterates over a collection of data and directly accesses its values instead of its keys or indices. Below, a for…of loop is used to access the values of strings and arrays.
Below, see how a for…in loop is used to iterate over an array and access each index (instead of the value of each index).
Note: It is advised to use for…in loops for objects but not for arrays. This is because a for…in loop will iterate through custom properties on an array.
To avoid side effects like the unexpected behavior seen in the example above, only use for…in loops for objects.
Set Objects are data structures released by ES6 that are very similar to arrays. Much like arrays, Set Objects :
However, there are several key differences between Sets and arrays:
Below, we see an example of a new Set object being initialized with the label setEx. Notice how only one string of ‘hi’ is found in setEx and, on line 12, we can convert it into an array and assign it to the variable setAsArray.
Another key advantage of using Sets over Arrays is that Sets are more efficient when it comes to looking up their values. Lookup operations in Sets are much faster (usually O(1) - constant). Below, invoking setEx.has() is faster than invoking arrayEx.includes() because the Array.includes() must iterate through the entire array whereas Set.has() does not.
Be sure to check out other useful Set methods like delete(), clear(), size(), forEach(), values(), and more and you’ll quickly find how powerful these data structures can be!
Map objects are another useful data structure in ES6 JavaScript that share some similarities with regular objects, but also offer some improvements in functionality for dealing with key-value pairs. Much like objects, Maps:
The main differences and improvements that Maps bring to the table, include:
The example below:
This example would work well for basic cases, but here’s an example of how Map objects open up the realm of possibility:
The example above details the following:
Creating a new Map object:
Adding entries to the Map object:
Checking for Keys:
Deleting Entries:
Maps are a major efficiency upgrade in working with key-value pairs. Be sure to check out other useful Map methods, like .clear(), .size(), and .forEach().
ECMAScript 6 introduced many useful global methods- methods (functions) that can be used anywhere in your code without calling a new instance of an object or class. Some of the most popular global methods in ES6 JavaScript include:
Array.from() - converts data types with length properties into true arrays. You may pass a second argument to it, which can be a map function to transform elements as you convert them into an array.
Array.find() - finds the first instance of an element in an array that satisfies a provided function.
Array.findIndex() - very similar to Array.find() but returns the index of the first element in an array that satisfies a provided function.
String.includes() - returns whether or not a string includes a specified substring.
String.startsWith() - checks if a string starts with the specified substring.
String.endsWith() - checks whether or not a string ends with a specified substring.
Other popular ES6 global methods include:
Number.isNaN() - determines if the passed in value is not a number.
Number.isInteger() - determines whether or not the passed in value is an integer.
Math.sign() - returns whether the passed in number is positive, negative or null.
Math.trunc() - returns a number with any fractional digits removed (ie: 4.25 => 4)
The Global methods in ES6 JavaScript are incredibly useful as they provide an optimized and easily readable standard for executing common tasks in your code. Whether you’re solving algorithms or developing a program, you’ll find yourself using these pre-built functions quite a bit!
A wonderfully flexible feature in ES6 Javascript was the introduction of modules. In essence, a module is a Javascript (.js) file that uses the import and export keywords to define dependencies and make variables, objects, and functionality available to other files. This feature allows you to modularize your code by splitting it into reusable pieces.
To export items from a module, you can either use a default export, or named exports. The default export is used to make a single primary value available, often when a module has one specific purpose. The keywords export default are used, followed by the value you want to export. For example:
When using named exports, you can make multiple items available to other modules by using the export keyword before the declaration of your function, variable, or object, like this:
To use your exports in another module, you need to bring them into the file with an import declaration. To bring in named exports, use the import keyword, list the names in curly braces, add from, and specify the module’s path in quotes. Importing a default export is similar but doesn’t require curly braces, and you can rename it as long as the origin path is correct. For example:
You can even mix and match imports, combining named exports and the default export from the same module. If you have a group of related functions or items, you can bundle everything into an object to use as the default export, making it all available with a single import.
Modules are like the Tupperware of Javascript –a convenient, reusable way to store, organize, and share your code within the codebase. Bonus: no spaghetti stains.
ES6 JavaScript introduced some of the most groundbreaking features that engineers use in their code every day. From the introduction of the const and let keywords, to spread and rest syntax to ES6 modules, and everything in between, this powerful update has revolutionized the way in which engineers write clean, efficient, and maintainable code. We encourage you to try them out for yourself and check out the Codesmith blog for articles that dive deeper into these ES6 features.
Not at all. By introducing the features mentioned in this article, ES6 has laid the foundation for massive improvements in JavaScript making it more concise and readable. Because of this, ECMAScript has continued to evolve, helping JavaScript maintain its status as the most relevant and popular scripting language today.
If you’re new to software development, you can take comfort in knowing that you’re starting in the right place with JavaScript as it is relatively straight forward (though some of these concepts may feel a bit confusing at the moment) and it is one of the only languages that can be used for front and back end development. JavaScript also has a massive community of support meaning that you’ll have countless resources to help you learn and grow throughout your journey. Happy scripting!
ECMAScript7 was released in June of 2016 and is considered to be a relatively incremental update compared to ES6 as it added only a few major features to the language. Although it is not considered to be a major improvement from previous versions, ECMAScript 7 is still regarded as one of many important steps toward JavaScript as we know it today.
EMCAScript7 offered fewer new features than its predecessor but was still a step toward making JavaScript more functional and readable. The two most notable updates were:
(ie: console.log(2 ** 3) // logs 8)
Explore CS Prep further in our beginner-friendly program.
Get more free resources and access to coding events every 2 weeks.
Connect with one of our graduates/recruiters.
Our graduates/recruiters work at:
Sam and Alex are writing partners, content creators, proud Codesmith alumni, and best friends. Former professional dancers/actors, the two transitioned into software development from musical theatre to bring their creative energy and passion for storytelling into the world of tech — specifically in developer relations. Their mission is simple: make software development fun, accessible, and community-driven. Through comedy, empathy, and a deep understanding of what makes content resonate, Alex and Sam strive to build bridges between developers and the tools they love. Sam, a Lead Engineering Fellow at Codesmith, is known among students and colleagues for his empathetic teaching style, strong sense of responsibility toward his students, and infectious sense of humor. Alex, a Technical Content Creator at Codesmith, blends technical knowledge with storytelling and humor to turn complex topics into engaging, easy-to-understand content.
Connect with one of our graduates/recruiters to learn about their journeys.
Our graduates/recruiters work at: