7 Javascript Concepts to Master Before Any Framework / Library
A simple guide to essential modern JavaScript
JavaScript libraries/frameworks like React or Vue are ruling the web development world. But to truly appreciate their power, you must have a good understanding and command of certain modern JavaScript concepts.
If you know JavaScript but haven't yet worked with ES6 or any other modern version of JavaScript, then jumping right into something like React might seem terrifying. You might not even recognize it as JavaScript and wonder which new alien language it is.
Relax! You can pick-up these in no time. This article will serve as your simple reference. Don't forget to bookmark it. Also, don't forget to check out the resources section at the end of this article for further reading.
Buckle up… going we’re lightspeed…
1. Understand “let” and “const”
I am sure you might be familiar with var
¹, the quintessential keyword to create variables in JavaScript. We know that in the course of a program some variables really do not change. They are so-called constants. Technically though they are all just variables because JavaScript only knows var
.
With ES6, a newer version of JavaScript, two different keywords were introduced let
² and const
³.
Sure var
still works but you are highly encouraged to use let
and const
. Let
is like the new var
, you use it for variable values.
The most important takeaway here is to use
let
if you want to create a variable that really is a variable or changes its value. Useconst
if you are creating a constant value, like something that you assign once and never change. This is the case more often than you think when you are using modern JS frameworks / libraries.
Let's have a quick look at how they work. During the older var
days we would do something like this
var userName = 'John';
console.log(userName);
Then if we re-assign a new value to username
userName = 'Doe';
console.log(userName);
Let's Run it. You will see John
printed first followed by Doe
Now instead of var
we use let
let userName = 'John';
console.log(userName);userName = 'Doe';
console.log(userName);
When you rerun the code, you will see the same output, and nothing changes. So let
works essentially as var
. So, what's the big deal?
var
declarations are globally scoped or function/locally scoped. Whereaslet
is block-scoped i.e anything within the curly braces{}.
Also,var
variables can be re-declared and updated.let
variables can only be updated but not re-declared. Here’s a good article from freecodecamp diving deeper into this difference.
Let's look at const
now
const userName = 'John';
console.log(userName);userName = 'Doe';
console.log(userName);
Now if you try to run it, You will see John
printed first, followed by an error message.
TypeError: Assignment to constant variable.
This is because the value of a const
can’t be changed through reassignment, and it can’t be redeclared.
2. Arrow Functions and how to use them
Oh boy. This one gets me most excited. Another construct that you’ll come across the most is the arrow functions⁴. It’s not just syntactic sugar for declaring functions but also how this
keyword behaves with arrow functions.
A normal JavaScript function looks like this with the function
keyword.
function doSomething() {
// some more logic...
}
Or you’d have used it as a function expression as
var doSomething = function() {
// Some more logic ...
}
now, this is how an Arrow function looks like. Also, known as Fat arrow functions.
const doSomething = () => {
// Some more logic...
}
Here we’re storing the function reference into a constant and on the right-hand side of =
is the arrow function’s syntax. A list of arguments go into the parenthesis ()
. Here it's none, followed by the =>
or the arrow, which is followed by the function body between the curly parenthesis {}
.
Arrow function not only has a shorter syntax due to omission of the
function
keyword, it also provides benefits and clears a lot of confusions we used to have with the dreadedthis
keyword.Understanding how the notorious
this
keyword works is a nice rabbit hole to fall into. Take a read of these medium articles here⁵ .
Let us see a few examples and variations of arrow functions. First, let's start with a normal function as a reference point
function printUserName(userName) {
console.log(userName);
}printUserName('John');
The output is John. The arrow function equivalent will look like this (Of course you will use let
instead of const
if you plan to reassign the function )
const printUserName = (userName) => {
console.log(userName);
}printUserName('John');
You will still see John As the output. Let’s look at a few alternatives to this syntax. If you only receive one (exactly one!) argument, you can use the short cut of omitting the parenthesis, like so
const printUserName = userName => {
console.log(userName);
}printUserName('John');
However, if you have a function that receives no arguments whatsoever, then you will have to use the empty parenthesis like so
const printUserName = () => {
console.log('John');
}printUserName();
Likewise, for more than one arguments, you have to use the parenthesis
const printUserName = (userName, age) => {
console.log(userName, age);
}printUserName('John', 28);
These are the different variations regarding arguments. There is also a different alternative regarding the function body. If you have a function that just returns something like, say a square of a number. We can have a short form arrow function like this where you omit the curly braces and also the return
keyword.
const squared = number => number ** 2;
console.log(squared(3));
3. Learn Exports⁶ and Imports⁷ for Modular code
Learning how to write modular JavaScript is essential, even if you are not using any Frameworks / Library. The code is split over multiple files for better maintainability and reuse.
The idea behind export
and import
statements or so-called modules is that inside of a JavaScript file we can import content from another file. So that the JavaScript files themselves know their dependencies.
It might look like this
First file person.js
we have a constant
person which stores a JavaScript object. we have a default export of this file using the export
and default
keywords.
We also have another file utility.js
where we export multiple things, a constant
named clean
which holds a function and baseData
which holds a number.
We have a third file app.js
. We are importing from person.js
and utility.js
. which requires a couple of import
statements.
We see person.js
uses the default
keyword. It merely means that if we import something from that file it will be the default export. In our case, it will be the person
constant. Hence we can name person
whatever we want in app.js, you can see that in the first two statements in app.js we are importing person.js but with two different names person
and prs
, the name doesn't matter.
utility.js
is a bit different, we are importing from two different constants and therefore we use the curly braces {}
to explicitly target specific things from that file. These are called named exports. It is important to provide the exact names as in utility.js
. You can also write this as one statement
import {clean, baseData} from './utility.js'
With default export, you have the liberty to name it as you will
import person from './person.js'
import prs from './person.js'
With named export, you can do this
import {clean} from './utility.js'//also use an alias
import {clean as cln} from './utility.js'//or import everything with * with an alias and use it as bundled.clean
import * as bundled from './utility.js'
3. Understand Classes⁸
Classes are from the object-oriented programming world and yes you can use them in JavaScript too.
Think of classes as blueprints/templates for creating objects. They are like the cookie cutter to make cookies, where cookies are the objects. Another example is using stencils to draw shapes, where the stencil is the class and the shapes are objects.
You define a class using the class
keyword. A class can have both properties and methods. A property is a variable attached to the class. Methods are functions attached to classes. In the following code-snippet person
is a class
with name
as property and call
is a method
class Person {
name = 'John'
call = () => {// Some logic...}
}
When you want to create an object
using a class
, its called instantiating a class. You use the new
⁹ keyword to instantiate a class ( in other words create an object).
const myPerson = new Person()
myPerson.call()
console.log(myPerson.name)
classes also support inheritance. You can potentially inherit all the properties and methods from another class and adding new ones to your inherited class. You use the extends
keyword to inherit from classes.
class person extends Human
Let's look at a quick example of class
class Person {
constructor() {
this.name = 'John';
}
printMyName() {
console.log(this.name);
}const person = new Person();
person.printMyName();
The output is John
In the example above, we have defined a class
Person
. You will notice that we have used a constructor
function. Constructor functions allow you to set the default characteristics to the object that is created.
Also, you will notice that we have used the this
keyword to refer to the current instance of the class.
Let's look at a quick example of inheritance¹⁰ using the same class
class Human {
constructor () {
this.gender = 'male';
}
printGender() {
console.log(this.gender);
}
}// Inherit from Human Class
class Person extends Human {
constructor() {
super();
this.name = 'John';
}
printMyName() {
console.log(this.name);
}const person = new Person();
person.printMyName();
person.printGender();
Here Person class inherits/extends the Human class. You will notice that even the Human class has the constructor function. To access the constructor in the Human class, we have to use the super()
function.
You’ll encounter classes more often especially in React for class-based components.
4. Use NextGen Properties and Methods in Classes
The NextGen JavaScript also offers a new syntax for initializing properties and methods.
We already learnt that properties are like variables attached to classes/objects. Methods are like functions attached to properties/objects.
Using ES6 format we have seen constructors used as such in classes
constructor () {
this.myProperty = 'value'
}
With NextGen JavaScript, we can assign property directly in the class, skipping the constructor function. Behind the scenes, this will still be transformed into a constructor function, but you’ll have an easier time writing this.
myProperty = 'value'
It’s pretty similar to methods. In ES6 we would have the methods as
myMethod () {...}
The NextGen JavaScript way is to use syntax similar to setting a property. Simply think of a method as a property that stores a function as a value and then we end up with
mymethod = () => {...}
One good advantage of this is since we use the arrow function as a property value we’ve got no problems with the confusing this
keyword.
To see this in action, we can modify the example from the previous section as such
class Human {
gender = 'male';
printGender = () => {
console.log(this.gender);
}
}// Inherit from Human Class
class Person extends Human {
this.name = 'John';
printMyName = () => {
console.log(this.name);
}const person = new Person();
person.printMyName();
person.printGender();
5. The helpful Spread¹¹ & Rest¹² Operators
Let's now look at two new operators that will make our life easier as developers. They are the spread and the rest operator. Interestingly they look the same …
(3 dots). Depending on where you use them, they behave either as spread or rest operators.
The spread operator is used to split up array elements or object properties. So we “spread up” an array or object.
For example, if we have an old array and we want to add all the elements from the old array to a new array and additionally add a couple of elements this is the syntax we’d use.
const newArray = [...oldArray, 1,2]
the …
in front of oldArray
will simply pull out all the elements and add them to the new array. The same applies to an object
const newObject = {...oldObject, newProp: 3}
Here the …
pulls out the oldObject
and the values to add them as key-value pairs of the newObject
. As a side note if the old object already had a newProp,
it will be overwritten by newProp with value 3 here.
Now let's look at the Rest operator. It’s the same …
operator but used differently, here it is used to merge a list of function arguments into an array. Here’s an example
const sortArgs = (...args) => {
return args.sort()
}
sortArgs
function receives an unlimited amount of arguments, with …
, we only write one argument args
. But we may receive more than one argument and they will all be merged into an array. We can apply array methods to our argument conveniently.
6. Destructuring¹³
Destructuring allows us to easily extract array elements or object properties and store them in variables.
I know you are thinking, it sounds like the exact thing the spread operator does. Hear me out!
Spread takes out all elements or all properties and distributes them in a new array or object. Destructuring allows us to pull out single elements or properties and store them in variables.
For Arrays, it looks like this
[a,b] = ['Hello','John']
console.log(a) // prints Hello
console.log(b) // prints John
If we have an array with two elements — Hello and John, then we can use the strange-looking syntax on the left-hand side of the equal sign to assign the variables a
and b
to Hello
and John
respectively
For object destructuring, it’s the same syntax but with the curly braces {}
.
{name} = {name:'John', age:28}
console.log(name) // Prints John
console.log(age) // undefined
In array destructuring the order defines which property we take, for object destructuring its the property name. so {name}
on the left-hand side of the =
sign targets the name
property on the right side and pulls out the value. This is why logging age
property would yield undefined
.
7. Refreshing Primitive¹⁴ and Reference¹⁵ Types
This isn’t a modern JavaScript concept, but it is super important that you understand this right. It can save you from unintentionally sacrificing many nights debugging!
If we create a number like this, this is a primitive type
const number = 5
Now if we create a second number num2
and assign it to number
, This actually creates a real new copy of number
and assigns the value to num2
.
const num2 = number
console.log(num2) // prints 5
numbers, strings booleans are primitive types. When ever you reassign or store in another variable a real copy is created.
If we look at objects and arrays
const person = {
name = 'John'
}
Now if we create a second object secondPerson
and assign person
as a value
const secondPerson = person;
console.log(secondPerson); // prints same vale as person
When we log the value of secondPerson
, it prints the same value as person
. It will not have copied the person
instead, person
the object is stored in memory and the pointer to this memory location is copied to secondPerson
.
Now if we change person
name property after assigning it to secondPerson
, still, we will see the new value of person
logged for secondPerson
.
const secondPerson = person;
person.name = 'Doe'
console.log(secondPerson); // prints same value as updated person
This is the same behavior with arrays. This becomes very important as it can lead to unexpected behavior in code. If you copy arrays or objects like this with an intention to create actual copies this won't work!
To create actual copies for reference types we can use the spread operator …
. So our modified code will look like this
const person = {
name = 'John'
};const secondPerson = {
...person
};
Now seconPerson
is an actual copy. Modifying person
will not affect secondPerson
.
Conclusion
If you made it this far, Bravo! Thank you for taking the time. Now don't be intimidated by these new syntaxes, this is still JavaScript. The best way to imbibe these is by practice. I encourage you to go back to previous sections and practice, for further reading check out the resources section. Happy hacking!
You might also like:
Resources
The source of truth when it comes to JavaScript is definitely Mozilla Developer Network (MDN).
- MDN reference on
var
- MDN reference on
let
- MDN reference on
const
- MDN reference on arrow functions
- Understanding
this
keyword in javascript - MDN reference on
export
and default exports - MDN reference on
import
- MDN reference on Classes
- Understanding
new
Keyword on MDN - Learn more about inheritance in JavaScript on MDN
- MDN reference on Spread Syntax
- MDN rest parameter syntax
- MDN reference on Destructuring
- MDN reference on Primitive types
- Reference types in Javascript