Advanced JavaScript


On this topic, we shall learn some advanced JavaScript concepts that’ll enable us have better understanding of JavaScript which can later be applied on frameworks such as React.
Topics
The topics we shall dwell in on this journey towards Java
Arrays:
Here we will learn the following;
Fundamentals of arrays
Accessing array elements
Basic operations on Arrays (Array methods)
Objects
Under Objects, we shall explore the following;
The key concepts of objects
Structure of object
Object properties and methods.
ES6+ Features
We shall delve deep by understanding ES6, where we shall learn the following;
Modern JavaScript features such as let, const, arrow functions
Template literals
Destructuring, spread, and rest operators.
Arrays in JavaScript
In JavaScript, an Array is a variable that can hold multiple values together. The values within an array are called elements and can be accessed by numerical indices.
A JavaScript array has the following characteristics:
Arrays are resizeable and can contain a mix of different data types. For example, you have an array that stores elements with the types numbers, string, boolean, and null. Their size is also dynamic and auto-growing, and therefore you don’t need to specify the array size up front.
JavaScript arrays are zero indexed. Meaning, the first element in array starts at index 0 while the last element is at array’s length minus 1.
JavaScript arrays are associative and so elements cannot be accessed using arbitrary strings as indexes, but must be accessed using non negative integers as indexes.
1.1. Creating/Declaring an Array
JavaScript provides us with two main ways to declare an array variable.
- Using square brackets
[]
.
Arrays can be created using square brackets []
to wrap comma-separated list of elements together. It is the most common way of creating/declaring arrays in JavaScript.
For instance, here is an example that creates countries
array that hold string elements.
// Creating an array of countries using square brackets
let countries = ['Kenya', 'Uganda', 'South Africa', 'Nigeria'];
To create an empty array, you use the square brackets without necessarily specifying any element as shown below;
// Creating an empty array using square brackets
let countries = [];
- Using the
Array
constructor.
This method of array declaration is not common compared to the use of square brackets.
It can be used as shown below;
// Creating an empty array using Array constructor
let countries = new Array();
If you happen to know the number of elements the array will hold, you can create an array with an initial size as shown below;
// Creating an array with defined number of elements
let countries = Array(5);
To create an array and initialize it some known elements, you can pass the elements as comma separated list into the Array()
constructor as shown below;
// Creating array and initializing elements
let countries = new Array('Kenya', 'Uganda', 'South Africa', 'Nigeria', 'Ghana');
1.2. Accessing JavaScript Array elements
JavaScript arrays are zero indexed like I had mentioned before. Meaning, the first element starts at index 0, the second element starts at index 1 and so on.
Therefore, to access an element in an array, you have to specify the index of an element in the square brackets []
.
This can be done as shown below;
arrayName[index];
Here is how to access elements of the countries
array:
let countries = ['Kenya', 'Uganda', 'South Africa', 'Nigeria'];
console.log(countries[0]); // Output: Kenya
console.log(countries[1]); // Output: Uganda
console.log(countries[2]); // Output: South Africa
console.log(countries[3]); // Output: Nigeria
To change the value of an element, you assign that value to the element as shown below;
let countries = ['Kenya', 'Uganda', 'South Africa', 'Nigeria'];
countries[2] = 'Botswana';
console.log(countries); // Outputs: ['Kenya', 'Uganda', 'Botswana', 'Nigeria']
Getting array size
To get the size of an array, we use the length property of an array which then returns the number of elements within the array. Here is how to use the length property.
let countries = ['Kenya', 'Uganda', 'South Africa', 'Nigeria'];
console.log(countries.length); // Outputs: 4
1.3. Basic operations Arrays
In this section, we’ll get to learn some basic operations that you can perform on an array elements.
They include the following:
- Adding an element to an array
To add an element to the end of an array, you use the push()
method, which looks something like this:
let countries = ['Kenya', 'Uganda', 'South Africa', 'Nigeria'];
countries.push('Tanzania');
console.log(countries); // Outputs: ['Kenya', 'Uganda', 'South Africa', 'Nigeria', 'Tanzania']
- Adding an element to the beginning of an array
To add an element at the beginning of an array, you use the unshift()
method which looks something like this.
let countries = ['Kenya', 'Uganda', 'South Africa', 'Nigeria'];
countries.unshift('Tanzania');
console.log(countries); // Outputs: ['Tanzania', 'Kenya', 'Uganda', 'South Africa', 'Nigeria']
- Removing an element from the end of an array
To remove an element from the end on an array, you use the pop()
methods. Popping reduces the length of an array.
It looks something like this:
let countries = ['Kenya', 'Uganda', 'South Africa', 'Nigeria'];
let lastCountry = countris.pop();
console.log(lastCountry); // Outputs: Nigeria
- Removing an element from the beginning of an array
To remove an element from the beginning of an array, you use the shift()
methods. Shift also reduces the length of an array.
It looks something like this:
let countries = ['Kenya', 'Uganda', 'South Africa', 'Nigeria'];
let firstCountry = countris.shift();
console.log(firstCountry); // Outputs: Kenya
- Finding an index of an element in the array
To find an index of an element, you use the indexOf()
method which looks something like this:
let countries = ['Kenya', 'Uganda', 'South Africa', 'Nigeria'];
let index = countris.indexOf('Kenya');
console.log(index); // Outputs: 0
- Checking if a value is an array
To check if a value of variable is an array, we use the Arrray.isArray()
method, which looks something like this:
console.log(Array.isArray(countries)); // Outputs: true
JavaScript Objects
JavaScript objects can be define as unordered collections of key-value pairs, where keys are strings and values can be any data type.
They offer a convenient way to organize and access related data.
An example of a JavaScript Object is as shown below:
let student = {
firstName: "Lord",
lastName: "Abiolla",
year: 2020,
course: "Frontend Engineering"
};
The firstName
, lastName
, year
, and course
in this case are the properties which can be accessed using the dot notation or bracket notation.
2.1. Object declaration
JavaScript objects can be declared in a few different ways which may include:
- Object Literal Syntax
This forms the most common way of creating an object in JavaScript. It involves defining the property and value within a curly braces {}
Example:
let object = {
key1: 'value1',
key2: 'value2'
key3: 'value3'
};
- Object Constructor
Object Constructor is another way you can use to create an object but it is not as commonly used as the literal syntax.
Example:
let object = new Object();
object.key1 = 'value1';
object.key2 = 'value2';
object.key3 = 'value3';
- Constructor Function
Constructor functions can mostly be used to create multiple objects with the same structure.
Example:
function MyObject(key1, key2, key3) {
this.key1 = key1;
this.key2 = key2;
this.key3 = key3;
}
let object = new MyObject('value1', 'value2', 'value3');
2.2. Object Properties
JavaScript object properties can be read using either dot notation
or bracket notation
.
- Dot Notation
let object = {
key1: 'value1',
key2: 'value2',
key3: 'value3'
};
console.log(object.key1); // Outputs: 'value1'
- Bracket Notation
let object = {
key1: 'value1',
key2: 'value2',
key3: 'value3'
};
console.log(object['key1']); // Outputs: 'value1'
Updating Object Properties
JavaScript object properties can also be updated using either dot notation or bracket notation
- Dot Notation
let object = {
key1: 'value1',
key2: 'value2',
key3: 'value3'
};
object.key1 = 'new value1';
console.log(object.key1); // Outputs: 'new value1'
In the above snippet, we are updating the property key1
to a new value ‘new value1‘
.
- Bracket Notation
let object = {
key1: 'value1',
key2: 'value2',
key3: 'value3'
};
object['key1'] = 'new value1';
console.log(object['key1']); // Outputs: 'new value1'
In the above snippet, we are updating the property key1
to a new value ‘new value1‘
.
2.3. Adding Object Properties
To add properties to an object after it has been created, again we can choose to either use the dot notation
or bracket notation
.
- Dot Notation
let object = {
key1: 'value1',
key2: 'value2'
};
object.key3 = 'value3';
console.log(object.key3); // Outputs: 'value3'
- Bracket Notation
let object = {
key1: 'value1',
key2: 'value2'
};
object['key3'] = 'value3';
console.log(object['key3']); // Outputs: 'value3'
In the above examples, we are adding a new property key3
to the object
.
2.4. Deleting Object Properties
In JavaScript, properties can be deleted from an object using the delete
operator.
This can be done as demonstrated below.
let object = {
key1: 'value1',
key2: 'value2',
key3: 'value3'
};
delete object.key1;
console.log(object.key1); // Outputs: undefined
Above here, we are deleting the property key1
from the object, object
. After deletion operation, when we try to access the object.key1
, it returns undefined
because the property no longer exists.
2.5. Checking if a Property Exists
We can always check if a property exists in an object in several ways as listed below.
- Using the
in
operator
The in
operator enables us iterate through an object and if it finds an occurrence of our property, it returns true
.
Example:
let object = {
key1: 'value1',
key2: 'value2'
};
console.log('key1' in object); // Outputs: true
console.log('key3' in object); // Outputs: false
- The
hasOwnProperty
method
This is a method which returns true
if the object has the specified property as its own property, and that the property is not inherited.
Here is how it works:
let object = {
key1: 'value1',
key2: 'value2'
};
console.log(object.hasOwnProperty('key1')); // Outputs: true
console.log(object.hasOwnProperty('key3')); // Outputs: falseobj
- Direct Property Access.
This is another way of checking if a property exists by checking if the property value is undefined
.
This method can sometimes give false negative if the property exists in the object but has its value set as undefined
.
let object = {
key1: 'value1',
key2: 'value2'
};
console.log(object.key1 !== undefined); // Outputs: true
console.log(object.key3 !== undefined); // Outputs: false
2.6. Iterating Over Object Properties
To iterate simply means to move through the object. We can iterate/move through the properties of an object using a for...in
loop as shown below;
let object = {
key1: 'value1',
key2: 'value2',
key3: 'value3'
};
for (let key in object) {
if (object.hasOwnProperty(key)) {
console.log(key + ': ' + object[key]);
}
}
/*
key1: value1
key2: value2
key3: value3
*/
The for ... in
loop iterates over each property in the object, and the hasOwnProperty
method ensures that the property belongs to the object itself and not its prototype.
At the end of the iterations, we get an output as shown below the code snippet.
2.7. JavaScript Object Methods
Methods in objects are functions that are stored within the object as object properties. The method name becomes the property while the body of the function is the value.
let object = {
property1: 'value1',
property2: 'value2',
method: function() {
console.log('This is a method!');
}
};
// Call the method
object.method(); // Outputs: 'This is a method!'
method
in this case is a method/function within the object object
. You can call the method using the object name followed by the method name.
Moreover, you can use the this
keyword in methods to refer to the object. This can be done as follows.
let object = {
property1: 'value1',
property2: 'value2',
method: function() {
console.log('Property1 is ' + this.property1);
}
};
// Call the method
object.method(); // Outputs: 'Property1 is value1'
this.property1
within the method refers to the property1
of the object object
.
ES6+ Features
ES basically means ECMA Script. It is a standard for scripting languages. Meaning, when writing JavaScript, it is basically an implementation of ECMA Script.
The current version of ECMA Script is ES6 and is not supported in some other browsers.
In order to translate your code to ES5 which is compatible with most browsers, we use a transpiler which converts ES6 code to ES5. Examples of those include; Babel
, Google Chrome Canary, which is google’s developing browser.
3.1. let and const
Before advent of ES6, var
was the way to declare variable. Issues therefore started arising with the declaration of var
and that is why it was necessary for new ways to declare variables to emerge
First let understand var
and it’s problems.
Scope of var
Scope basically means where these variables are available for use. var
declarations are globally scoped or function/locally scoped.
The scope is global when a var
variable is declared outside a function. Meaning, any variable declared with var
outside a function block is available for use in the whole window.
var
is function scoped when it’s declared within a function. Meaning, the variable is available and can be accessed only within that function.
Here is an example to understand this further:
var greet = "Hello World";
function newFunction() {
var hello = "Hello";
}
In the above snippet, greet
is globally scoped because it exists outside a function while hello
is function scoped. Therefore, we cannot access the variable hello
outside of a function.
If we try accessing the hello
variable outside the function, we get a not defined error
as shown bellow.
var greet = "hey hi";
function newFunction() {
var hello = "hello";
}
console.log(hello); // error: hello is not defined
var
variables can also be re-declared and updated within the same scope without getting an error. This can be done as shown.
var greeter = "hey hi";
var greeter = "say Hello instead";
Hoisting is a JavaScript mechanism where variables and function declarations are moved to the top of their scope before code execution.
Meaning, if we do this:
console.log (greeter);
var greeter = "say hello"
it is interpreted as this:
var greeter;
console.log(greeter); // greeter is undefined
greeter = "say hello"
so var
variables are hoisted to the top of their scope and initialized with a value of undefined.
So, what exactly is the problem of var
? Let’s use an example:
var greeter = "hey hi";
var times = 4;
if (times > 3) {
var greeter = "say Hello instead";
}
console.log(greeter) // "say Hello instead"
So, since times > 3
returns true, greeter
is redefined to "say Hello instead"
. While this is not a problem if you knowingly want greeter
to be redefined, it becomes a problem when you do not realize that a variable greeter
has already been defined before.
If you have used greeter
in other parts of your code, you might be surprised at the output you might get. This will likely cause a lot of bugs in your code. This is why let
and const
are necessary.
Let is now preferred for variable declaration. It's no surprise as it comes as an improvement to var
declarations. It also solves the problem with var
that we just covered. This is so because:
let is block scoped: A block is a chunk of code bounded by {}. i.e., the code lives in the curly braces. Therefore, a variable declared with let
in only available for use within that block. Example:
let greeting = "say Hi";
let times = 4;
if (times > 3) {
let hello = "say Hello instead";
console.log(hello);// "say Hello instead"
}
console.log(hello) // hello is not defined
Here, using hello
outside its block (the curly braces where it was defined) returns an error because let
variables are block scoped.
Furthermore, let can be updated but not re-declared as shown below:
let greeting = "say Hi";
greeting = "say Hello instead";
but this will return an error.
let greeting = "say Hi";
let greeting = "say Hello instead"; // error: Identifier 'greeting' has already been declared
If a variable is declared more than once with the same name but in different scopes, there will be no error. Let’s take an example:
let greeting = "say Hi";
if (true) {
let greeting = "say Hello instead";
console.log(greeting); // "say Hello instead"
}
console.log(greeting); // "say Hi"
There is no error because both instances are treated as different variables since they have different scopes. This fact makes let
a better choice than var, and you as the programmer doesn’t have to bother if you have used a name for a variable before as a variable exists only within its scope.
For hoisting, let
variables are hoisted to the top. But unlike var
which is initialized as undefined
, let
keyword is not initialized and if you try to use a let
variable before declaration, you’ll get a Reference Error
.
Const variables maintain constant values, and share some similarities with let
declarations. They can be accessed within the block they were declared, but cannot be updated or re-declared.
This further means that every const
declaration must be initialized at the time of declaration.
While a const
object cannot be updated, the properties of this object can be updated. Therefore, if we declare a const
object as this:
const greeting = {
message: "say Hi",
times: 4
}
we can do this:
greeting.message = "say Hello instead";
Differences between const
, let
, and var
var
declarations are globally scoped or function scoped whilelet
andconst
are block scoped.var
variables can be updated and re-declared within its scope;let
variables can be updated but not re-declared;const
variables can neither be updated nor re-declared.All the three are hoisted at the top of their scope. But while
var
are initialized to undefined,let
andconst
variables are not initialized.While
var
andlet
can be declared without being initialized,const
must be initialized during declaration.3.2. Arrow function
ES6 arrow functions provide an alternative way to write a shorter syntax compared to the regular function expressions. The following example defines a function expression that returns the sum of two numbers:
let add = function (x, y) {
return x + y;
};
console.log(add(10, 20)); // 30
The following example is equivalent to the above add()
function expression but uses an arrow function instead:
let add = (x, y) => x + y;
console.log(add(10, 20)); // 30;
Key concepts of Arrow function
Arrow functions do not have the
function
keyword, they use=>
instead of thefunction
keyword.// Traditional function expression const greet = function(name) { return "Hello, " + name; }; // Arrow function expression const greet = (name) => "Hello, " + name;
Single parameters in arrow functions do not need parenthesis. Zero or more than one parameters need the parenthesis though.
// Single parameterized arrow function const double = x => x * 2; // Zero or more than one parameterized arrow function const sayHi = () => "Hi!"; const multiply = (a, b) => a * b;
JavaScript doesn’t allow a line break between the parameter definition and the arrow (
=>
) in an arrow function.For example:
// This code causes a SyntaxError: let multiply = (x,y) => x * y; // However, this code works perfectly fine let multiply = (x,y) => x * y; // OR let multiply = ( x, y ) => x * y;
Arrow vs. Regular functions
Feature | Arrow Function | Regular Function |
Syntax | Concise (with => ) | Verbose (Uses function ) |
this binding | Lexical (Outer scope) | Dynamic (this depends on how its called.) |
Can be used with new | No | Yes |
Has arguments object | No | Yes |
Common use case | Callbacks, Array methods | Constructors, methods, complex logic. |
3.3. Template Literals
Template literals are literals delimited with backtick(`) characters, allowing for multi-line strings, string interpolation with embedded expressions, and special constructs called tagged templates.
They can contain placeholders, indicated by the dollar sign and curly braces (`${expression}`
). The expressions in the placeholders and the text between them get passed to a function.
let name = "Lord";
let age = 27;
let greeting = `Hello, my name is ${name} and I am ${age} years old.`;
console.log(greeting); // Outputs: "Hello, my name is Lord and I am 27 years old."
Here, name
and age
are variables. The template literal is defined using backticks, and the variables are embedded in the string using `${}
` syntax. The resulting string is stored in the greeting
variable and then logged to the console.
The recommended way to format strings in JavaScript is by using Template Literals(Template Strings) introduced in ECMAScript 6 (ES6). Template Literals allow you embed expressions, create multi line strings, and use string interpolation features, making them a powerful tool for string formatting.
3.4. Destructuring
Destructuring in JavaScript is a syntax that allows one to unpack values from arrays or properties from objects, into distinct variables.
For example:
let fruits = ['apple', 'banana', 'cherry'];
let [fruit1, fruit2, fruit3] = fruits;
console.log(fruit1); // logs 'apple'
console.log(fruit2); // logs 'banana'
console.log(fruit3); // logs 'cherry'
In this example, the array fruits
is destructured into three new variables. The first element of the array is assigned to fruit1
, the second to fruit2
, and the third to fruit3
Destructuring also allows you skip over elements that you do not need.
let [fruit1, , fruit3] = fruits;
console.log(fruit1); // logs 'apple'
console.log(fruit3); // logs 'cherry'
The second element of the array is skipped and not assigned to any variable.
You can also destructure objects as follows:
let person = {
firstName: 'John',
lastName: 'Doe'
};
let { firstName, lastName } = person;
console.log(firstName); // 'John'
console.log(lastName); // 'Doe'
In the above example, we declare two variables firstName
and lastName
and assign them properties of the person object in the same statement.
It is possible to separate the declaration and assignment. However, you must surround the variables in parentheses. If you don’t use the parentheses, the JavaScript engine will interpret the left hand side as a block and throw a syntax error.
When you assign a property that does not exist to a variable using the object destructuring, the variable is set to undefined
. For example:
let { firstName, lastName, middleName } = person;
console.log(middleName); // undefined
In this example, the middleName
property doesn’t exist in the person
object, therefore, the middleName
variable is undefined
.
3.5. Spread and Rest Operators
Spread operator
ES6 provides us with a new operator called spread operator that consists of three dots ( . . . )
. The spread operator allows us to spread out elements of an iterable object such as an array, map, or set. It allows an iterable such as an array expression or string to be expanded in place where zero or more arguments or elements are expected.
Spread operator can be used to create new array and combine to another array:
let fruits = ['apple', 'banana', 'cherry'];
let moreFruits = [...fruits, 'date', 'elderberry'];
console.log(moreFruits); // logs ['apple', 'banana', 'cherry', 'date', 'elderberry']
Here, we are using spread operator . . . fruits
to expand the elements of fruits array into individual elements. The moreFruits
array is a new array that contains all the elements of the fruits
array, followed by date, and elderberry.
You can also use the spread operator to combine/concatenate two arrays as shown below:
let fruits1 = ['apple', 'banana'];
let fruits2 = ['cherry', 'date'];
let allFruits = [...fruits1, ...fruits2];
console.log(allFruits); // logs ['apple', 'banana', 'cherry', 'date']
...fruits1
and ...fruits2
expand the elements of the fruits1
and fruits2
arrays into individual elements. The allFruits
array is a new array that contains all the elements of the fruits1
and fruits2
arrays.
The spread operator also enables us copy an array as shown below:
let fruits1 = ['apple', 'banana'];
let fruits2 = [...fruits1];
console.log(fruits2); // logs ['apple', 'banana']
Rest operator
Rest operator also has three dots just like spread operator, but it’s the opposite of spread operator. Since spread operator expands array into it’s individual element, the rest operator collects multiple elements and collects them into a single array element.
You can think of it as a vacuum that “sucks up the rest” of the items into a box (array).
Rest operator is commonly used in function parameters, array destructuring, and object desructuring.
When you do not know how many arguments a function will receive, the rest operator lets you collect all of them into one array as shown below:
function sum(...numbers) {
console.log(numbers); // [1, 2, 3, 4]
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4)); // Output: 10
. . . numbers
collect all arguments passed to sum()
into an array called numbers
, then it allows you to loop or reduce them easily. Without the rest operator, you’ll need special arguments
object, which is less flexible and not available in arrow functions.
Rest operator can also be used to destructure/break an array to capture remaining element as shown below:
const fruits = ["apple", "banana", "mango", "orange"];
const [first, second, ...others] = fruits;
console.log(first); // "apple"
console.log(second); // "banana"
console.log(others); // ["mango", "orange"]
first
takes the first element, second
takes the second element, and . . . others
takes the rest into a new array.
In object destructuring, rest operator is also used to separate some properties from the rest in an object. For example:
const user = {
name: "Alice",
age: 25,
email: "alice@example.com",
location: "Nairobi"
};
const { name, ...otherDetails } = user;
console.log(name); // "Alice"
console.log(otherDetails); // { age: 25, email: "alice@example.com", location: "Nairobi" }
Here, name
is taken out, . . . otherDetails
collects the rest of the properties.
Subscribe to my newsletter
Read articles from Lord Abiolla directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Lord Abiolla
Lord Abiolla
Passionate Software Developer with a strong enthusiasm for data, technology, and entrepreneurship to solve real-world problems. I enjoy building innovative digital solutions and currently exploring new advancements in data, and leveraging my skills to create impactful software solutions. Beyond coding, I have a keen interest in strategic thinking in business and meeting new people to exchange ideas and collaborate on exciting projects.