Categories
JavaScript Basics

The Complete Guide to Using Arrays in JavaScript

Arrays are lists of objects that can be manipulated in various ways. Each entry can be accessed by their own index. Arrays can be combined in various ways and they can be also be nested in each other, letting us create multi-dimensional arrays. We can make arrays out of a collection of any objects. They can also be destructed into variables so each entry can be accessed and manipulated individually. JavaScript arrays are zero-indexed so the starting index of each array is always zero. This means that index 0 has the first element of the array.

Arrays can contain any type of object. They do not have to be the same type of objects. Also if an array entry with a given index hasn’t been assigned yet, it has an undefined value.

Examples of things that can be stored with arrays include:

  • to-do list
  • recipe list
  • address book contacts
  • shopping list
  • grocery list
  • your appointments
  • anything else that can be entered into a list.

Without arrays, all we can do is declare variables for each entry individually which is a real pain and not practical.

Declaring Arrays

To declare arrays, we use the let or const keyword — like this:

let arr = [1,2,3];
const arr2 = [1,2,3];

We use let for variables and const for arrays that don’t change.

Also, we can declare the arrays first and then insert the values later, like this:

let arr = []
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;

This is the same as let arr = [1,2,3] since we have the same entries and the same order in both arr arrays.

We can declare arrays with different type of values in the same array, like this:

let arr = [1, 'chicken', {foo: 'bar'}];

As you can see, it doesn’t matter what kind of data we put in the array. However, we do have to be careful to avoid data type errors when we traverse or manipulate arrays by checking the type and content of the objects, and whether any entry is null or undefined .

Another way to create an array is the new keyword, like this:

let names = new Array('Bob','Jane', 'John');

Accessing Array Data

We access array items by their index. For example, to get the second element of an array, we write:

arr[1]

If arr is assigned to [1, ‘chicken’, {foo: ‘bar’}]; , then arr[1] would be 'chicken' .

Get Array Size

Array is an object that has the length property that we can get the size of the array, so the names array we have above would have a length of three. We write the names.length to access the length of the array.

Multidimensional Arrays

In JavaScript, multidimensional arrays are just an array nested in another array. So, to declare a multidimensional array, we can use the same declaration methods as above, except we replace the entities inside with arrays. For example, we can write:

let multiArray = [[1,2,3], [4,5,6]];

or:

let multiArray = new Array([1,2,3], [4,5,6]);

We can also write:

let multiArray = [];
multiArray[0] = [];
multiArray[0][0] = 1;
multiArray[0][1] = 2;
multiArray[0][2] = 3;
multiArray[1] = [];
multiArray[1][0] = 4;
multiArray[1][1] = 5;
multiArray[1][2] = 6;

All three of these pieces of code are equivalent.

We access multidimensional array entries by adding another square bracket with the index of the inner array. For example, if we want to get the second item of the first array in multiArray then we write:

multiArray[0][1]

Traversing Arrays

We can traverse the values of arrays with loops. Loops are pieces of code that repeat until the ending condition is met. In JavaScript, we have the for loop, while loop and the do...while loop.

For Loop

With the for loop, given that we have the name array, we can traverse the loop by running:

let names = new Array('Bob','Jane', 'John');
for (let i = 0; i < names.length; i++){
  console.log(names[i]);
}

A for loop is usually written with the starting condition as the first statement, then the ending condition in the second statement, and the index changing condition in the third statement. The statements are separated by the semicolons. Because arrays start with index zero in JavaScript, we terminate the loop when the array’s index reaches one less than the array’s length.

While Loop

while loop will loop whenever a condition stays true.

For example, the loop below will run if the index number i is less than three:

const array = [1,2,3];let i = 0;
while(i < array.length){
  console.log(i);
}

If the condition in the parentheses is never true, then the loop content will never run.

Do While Loop

do...while loop will always execute the first iteration.

const array = [1,2,3];let i = 0;
do{
  console.log(i);
}
while(i < array.length)

In the example above, it will at least log 0, but it will also log 1 and 2 in this case since those two numbers are less than three.

With the above loops, you can call break to stop the loop or return before the loop is completely finished.

//do while loop
const array = [1,2,3];let i = 0;do{
  console.log(i);  if (i == 1}{    break;  }}
while(i < array.length)//while loop
i = 0;while(i < array.length){  if (i == 1{    break;  }
  console.log(i);
}//for loop
for (let j = 0; j < array.length; j++){  if (j == 1){
    break;
  }
  console.log(j);
}

In the above examples, you will not see two logged.

An example of returning from within the loop:

const loop = ()=>{
  const array = [1,2,3];
  for (let j = 0; j < array.length; j++){
    if (j == 1){
      return j;
    }
    console.log(j);
  }
}
loop() //returns 1

You can also skip iterations with the continue statement:

const array = [1,2,3];
for (let j = 0; j < array.length; j++){  if (j == 1){
    continue;
  }
  console.log(j) // 1 will be skipped;
}

Array Properties

Since an array is a JavaScript object. It is its own properties. Like any object in JavaScript, it has the prototype property which lets developers add methods and properties of an array object. The constructor property is the reference to the function that’s created by the array object’s prototype. The length returns the size of the array.

Array Methods

To make manipulating arrays easy, the JavaScript’s standard library contains lots of array methods that make manipulating arrays easy. There are methods to find and filter items, and add and remove items in an array for example. There are also functions to combine multiple arrays into one.

These are some common array methods that you can use to do common operations with arrays.

Array.forEach

forEach will iterate through every entry of the array. You cannot break out of it or return a value from it. It takes a callback function where you can execute code.

Example:

const array = [1,2,3];
  array.forEach(a =>{  console.log(a);
})

In the above example, all the numbers in the array will be logged.

Array.find

Array.find will return the element in the array with the given condition. For example, if you want to get certain numbers from the array, you do this:

const array = [1,2,3];
const num = array.find(a => a == 2); // returns 2

find returns a single result.

Array.findIndex

Array.findIndex will return the index of the element in the array with the given condition. It takes a callback function that returns a given condition. For example, if you want to get the index of a certain number from the array, you do this:

const array = [1,2,3];
const num = array.findIndex(a => a == 2); // returns 1

Array.filter

Array.filter will return an array of items that meet the given condition. It takes a callback function that returns a given condition. filter returns a new array.

For example, if you want to get the index of a certain number from the array, you do:

const array = [1,2,3];
const numArray = array.filter(a => a == 2); // returns [2]

Array.includes

Array.includes checks if an item exists in an array. It takes a number or string which the function can compare.

const array = [1,2,3];
const includesTwo = array.includes(2); // returns true

Array.some

Array.somechecks if some items meet the condition given. It takes a callback function which returns a boolean for the condition.

const array = [1,2,3];
const includesTwo = array.some(a => a == 2); // returns true
const includesFive = array.some(a => a == 5); // returns false

Array.every

Array.every checks if every item meets the condition given. It takes a callback function which returns a boolean for the condition.

const array = [1,2,3];
const everyElementIsTwo = array.every(a => a == 2); // returns false
const everyElementIsNumber = array.every(a => typeof a == 'number'); // returns true since every item in the array is a number

Array.isArray

Array.isArray checks if an object given is an array. It is a convenient way to check if an element is an array.

const array = [1,2,3];const notArray = {};
let objIsArray = Array.isArray(array); // true
objIsArray = Array.isArray(notArray); // false

Array.from(new Set(array))

Set is an object that cannot have duplicate entries. You can create a new Setfrom an array then convert it back to an array.

const array = [1,2,2,3];
const arrayWithDups = Array.from(new Set(array)); //returns new array without duplicates, [1,2,3]

Array.slice(startIndex, endIndex)

Returns a new array from startIndex to endIndex — 1 .

Example:

const arr = [1,2,3,4,5];
const newArr = arr.slice(0,2);
console.log(newArr); // returns [1,2]

Array.splice(index, numberOfItems)

Remove array item in place with the given index, and then numberOfItems after it.

For example:

const arr = [1,2,3,4,5];
arr.splice(0,2);
console.log(arr); // returns [3, 4, 5] since we specified that we remove item located at index 0 and 2 items after that.

Array.sort(sortFunction)

Array.sort sorts array in place according to the condition you return insortFunction .

The sortFunction should be in this format:

const sortFunction = (a, b) {
  if (a < b) {
    return -1;
  }
  if (a > b) {
    return 1;
  }
  // a must be equal to b
  return 0;
}

By default, if no sortFunction is specified, then the array items will be converted to a string and will be sorted according to the Unicode value of the string.

Array.fill(newElement, startIndex, endIndex)

Array.fill will add or replace the element with the element specified from startIndex to endIndex . If no startIndex is defined then it will start from 0. If no endIndex is defined, then it will change values up to the end of the array.

For example:

let array = [1, 2, 3, 4, 5];console.log(array.fill(0, 2, 4));
// array is now [1, 2, 0, 0, 0]console.log(array.fill(5, 1));
// array is now [1, 5, 5, 5, 5]console.log(array.fill(6));
// array is now [6, 6, 6, 6, 6]

Recursively Flatten Array

Array.flat function does not do a good job of recursively flatten arrays. The depth is limited and it does not flatten all kinds of nested array structures. The better way to do it is to write a recursive function to do it.

let arr1 = [1, 2, [3, 4], 5];
let arr2 = [1, 2, [3, 4], [5, [6,[7,]]]];const flatten = (items) => {
  const flat = [];  items.forEach(item => {
    if (Array.isArray(item)) {
      flat.push(...flatten(item));
    } else {
      flat.push(item);
    }
  });  return flat;
}console.log(flatten(arr1));
console.log(flatten(arr2));

Array.join(separator)

Array.join will return a string by concatenating the entries after they are converted to string with separator between each entry. Works best with string and number arrays.

Example:

const arr = [1,2,3];
console.log(arr.join(',')) // get '1,2,3'const arr = ['1',2,3];
console.log(arr.join(',')) // get '1,2,3'

Array.indexOf(elementToFind)

Array.indexOfwill return the first index of the elementToFind in the array. Works best with string and number arrays. If you want to find a non-string or number object, use Array.findIndex . Returns -1 is element is not found.

Example:

const arr = [1,2,3];
console.log(arr.indexOf(1)); // returns 0const arr2 = [1,1,2,3];
console.log(arr2.indexOf(1)) // still 0

Array.lastIndexOf()

Array.lastIndexOfwill return the last index of the elementToFind in the array. Works best with string and number arrays. Returns -1 is element is not found. The function also takes a starting index to start searching backward as a second parameter

Example:

const arr = [1,2,3];
console.log(arr.indexOf(1)); // returns 0const arr2 = [1,1,2,3];
console.log(arr2.indexOf(1)) // returns 1const arr3 = [3,1,2,3]
console.log(arr3.lastIndexOf(3, 2)) // returns 0, start searching backwards from index 2

Array.push(newElement)

Array.push adds a new element to an array.

Example:

let arr = [1,2,3];
arr.push(4);
console.log(arr) // [1,2,3,4]

Array.pop()

Array.pop removes the last element of the array.

Example:

let arr = [1,2,3,4];
arr.pop();
console.log(arr) // [1,2,3]

Array.map(mapFunction)

Array.map returns a new array which transforms the existing array’s element by calling the mapFunction . mapFunction takes one argument, which is the array element.

Example:

let arr = [1,2,3,4];
const newArr = arr.map(a=>a*2)
console.log(newArr) // [2,4,6,8]

Array.reduce(reduceFunction)

Array.reduce combines elements of an array to return a value by calling the reduceFunction on all the elements to combine them. reduceFunction takes two arguments, which is the current and next element in the array.

Example:

const arr = [1,2,3,4];
const sum = arr.reduce((a,b)=>a+b);
console.log(sum); // returns 10

Array.reverse()

Array.reverse returns a new array with the existing array’s elements in reverse order.

Example:

const arr = [1,2,3,4];
console.log(arr.reverse()) // [4,3,2,1]

Now that we learned about arrays, we can do a lot more in our JavaScript programs. There’s a big world ahead of us!

Categories
JavaScript Basics

How to Merge Arrays in JavaScript

Oftentimes, we need to combine multiple arrays into one array. With multiple arrays, combining them is pain without some help from JavaScript’s standard libraries. With ES6, there’s also the spread syntax to help us combine arrays.

There are a few ways to merge arrays in JavaScript.

Array.concat

We can all Array.concat on an array to combine 2 arrays and return the new one. For example:

const a = [1,2,3];
const b = [4,5];
const c = a.concat(b) // [1,2,3,4,5]

It also works with multiple arrays. You can pass in as many arrays as you want in the arguments of the concat function. For example:

const a = [1,2,3];
const b = [4,5];
const c = [6,7,8];
const d = a.concat(b, c) // [1,2,3,4,5,6,7]

Array.push

We can push elements of one array into another.

const a = [1,2,3];
const b = [4,5];
let c = Object.assign([], a);
for (let i = 0; i < b.length; i++){
  c.push(b[i]);
}
console.log(c); // [1,2,3,4,5]

What we did is make a copy of a and assigned it to c , then pushed the elements of b by looping through it and adding them to the end of c .

You can use the apply function available with all objects to combine 2 arrays. For example:

const a = [1,2];
const b = [3,4];
a.push.apply(a, b);
console.log(a); // [1,2,3,4];

Spread Operator

With ES6 or later, we can use the spread operator to spread the items from another array into a new array by doing the following:

const a = [1,2,3];
const b = [4,5];
const c = [...a, ...b];
console.log(c); // [1,2,3,4,5]
Categories
JavaScript Basics

How to Clone Array in JavaScript

There are a few ways to clone an array in JavaScript,

Object.assign

Object.assign allows us to make a shallow copy of any kind of object including arrays.

For example:

const a = [1,2,3];
const b = Object.assign([], a); // [1,2,3]

Array.slice

The Array.slice function returns a copy of the original array.

For example:

const a = [1,2,3];
const b = a.slice(0); // [1,2,3]

Array.from

The Array.slice function returns a copy of the original array. It takes array like objects like Set and it also takes an array as an argument.

const a = [1,2,3];
const b = Array.from(a); // [1,2,3]

Spread Operator

The fastest way to copy an array, which is available with ES6 or later, is the spread operator.

const a = [1,2,3];
const b = [...a]; // [1,2,3]

JSON.parse and JSON.stringify

This allows for deep copy of an array and only works if the objects in the array are plain objects. It can be used like this:

const a = [1,2,3];
const b = JSON.parse(JSON.stringify(a)); // [1,2,3]
Categories
JavaScript Basics

Using Default Parameters and the Rest Operator in JavaScript

With the 2015 version of JavaScript, JavaScript functions can now accept default parameters in functions and there’s the rest operator to capture optional arguments in an array.

This is handy for handling optional parameters and there are many use cases for these features. Before we had these two features, all we had was the arguments object with the list of arguments of the function that was called.

All we could do to prevent undefined errors for optional parameters was to check each argument directly to see if they were defined and then set the value directly.

This is painful for developers as it’s possible to have a long list of optional arguments that we want the function to get. With default parameters, the default value for parameters is set directly in the signature of the function. This eliminates many lines of code that check the code.


Default Parameters

Default parameters are easy with JavaScript. To set them in our code, we write the following:

const sum = (a,b=1) => a+b

In the code above, we set the default parameter value of b to 1, so if the second argument isn’t passed in when we call the sum function, then b is automatically set to 1.

So, if we call sum as follows, we get 2 returned:

sum(1)

As we can see, now we don’t have to worry about having optional arguments being undefined, which would be the alternative result if no default value is set for parameters. This eliminates many sources of errors that occur when making parameters optional with JavaScript.

The alternative way, without using default parameters, would be to check if each parameter is undefined. We write the following to do this:

const sum = (a,b,c)=>{
  if (typeof b === 'undefined'){
    b = 1;
  }

  if (typeof c === 'undefined'){
    c = 1;
  }
  return a+b+c;
}

If we call the following sum function without parameters, we get:

const sum = (a,b = 1,c = 1)=> a+b+c;
sum(1) // returns 3
sum(1, 2) // returns 4

As we can see, we handled missing parameters gracefully with default parameters.

For default parameters, passing in undefined is the same as skipping the parameters. For example, if we call the following function and pass in undefined, we get:

const sum = (a,b = 1,c = 1)=> a+b+c;
sum(1,undefined) // returns 3
sum(1,undefined,undefined) // returns 3
sum(1, 2,undefined) // returns 4

Note that undefined is the same as skipping parameters.

This isn’t true for other falsy values that are passed into a function. So, if we pass in 0, null, false, or empty string, they get passed in and the default parameter values will be overwritten.

For example, if we have the code below:

const test = (num=1) => typeof num;
test(undefined);
test(null);
test('');
test(0);
test(false);

We get number for test(undefined), object for test(null), string for test(string), number for test(0), and boolean for test(false).

This means that anything other than undefined is passed in, but note that if we pass in falsy values and then run arithmetic operations on them, falsy values get converted to 0.

const sum = (a,b = 1,c = 1)=> a+b+c;
sum(1,null)
sum(1,null,false)
sum(1, 2,'')

So, sum(1, null) returns 2 as b is converted to 0 and c has the default value of 1.

sum(1) returns 1 as b and c are converted to 0. sum(1, 2,’’) is 3 as a is 1, b is passed in so that it becomes 2 instead of getting the default value of 1, and c is an empty string which is converted to 0.

Default arguments are evaluated at call time, so that they’re set each time they’re called if no argument is passed into the function parameter with default values.

For example, if we have:

const append = (val, arr = [])=>{
  arr.push(val);
  return arr;
}

append(1);
append(2);

append(1) returns [1] and append(2) returns [2] as we didn’t pass in an array to each function call, so arr is set to an empty array each time it’s run.

It’s also important to know that we can pass in values returned by functions in the default parameter, so if we have a function that returns something, we can call it in the default parameter and assign the returned value to the parameter.

For example, we can write:

const fn = () => 2
const sum(a, b = fn()) => a+b;

Then, if we call sum(1), we get 3 as the fn function returns 2. This is very handy if we want to manipulate and combine values beforehand, before assigning it as a parameter.

Another great feature of the default parameters is that the parameters left of the given parameter are available for the parameter for assignment as default values, so we can have a function like the function below:

const saySomething = (name, somethingToSay, message = `Hi ${name}. ${somethingToSay}`) => ({
  name,
  somethingToSay,
  message
});

Notice that we assigned an expression to the message parameter in the saySomething function. This is great for manipulating data and then assigning as we did before by assigning the function.

We can also see that we can have default parameters that depend on parameters that are to the left of it. This means that default parameters do not have to be static.

So, we call it with the first two parameters filled in, like saySomething(‘Jane’, ‘How are you doing?’). We get:

{name: "Jane", somethingToSay: "How are you doing?", message: "Hi Jane. How are you doing?"}

The message is returned with the template string that we defined evaluated.

We cannot call functions nested inside a function to get the returned value as the default parameter value. For example, if we write:

const fn = (a = innerFn())=>{
  const innerFn = () => { return 'abc'; }
}

This will result in a ReferenceError being thrown, because the inner function isn’t defined yet when the default parameter is defined.

We can also have default parameter values that are set to the left of required parameters. Arguments are still passed into parameters from the left to the right, so if we have:

const sum = (a=1,b) => a+b

If we have sum(1), we have NaN return 1. It is added to undefined as we didn’t pas in anything for the second argument, so b is undefined.

However, if we write sum(1,2) then 3 is returned as we have a set to 1 and b set to 2.

Finally, we can use a destructuring assignment to set default parameter values. For example, we can write:

const sum = ([a,b] = [1,2], {c:c} = {c:3}) => a+b+c;

Then, we call sum without arguments. We get 6 because a is set to 1, b is set to 2, and c is set to 3 by the destructuring assignment feature that JavaScript provides.


Rest Operator

The rest operator is a JavaScript operator where we can store an indefinite number of arguments in a function as an array.

It looks exactly like the spread operator, which lets us spread entries of an array or a list of key-value pairs of an object into another object.

For example, if we have a function that has a long list of arguments, we can use the rest operator to shorten the list of parameters in a function.

The rest operator is used with the following syntax:

const fn = (a,b,..restOfTheArgs) => {...}

Where restOfTheArgs is an array with the list of arguments other than the first two. For example, if we want to write a sum function that takes an indefinite list of numbers as arguments and sum up the numbers, we can write:

const sum = (a,b,...otherNums) => {
  return a + b + otherNums.reduce((x,y)=>x+y, 0);
}

As we can see, this is very handy for functions that have a list of arguments. Before we had this, we had to use the arguments object available in functions to get a list of arguments.

This is not ideal, as we allow them to pass in anything into the arguments. With the rest operator, we have the best of both worlds. We can have some fixed parameters, while the rest stays flexible.

This makes functions more flexible than functions with a fixed number of parameters, while having some flexibility with functions that take an indefinite number of arguments.

The arguments object has all the arguments of the function. Also, it’s not a real array, so array functions aren’t available to them. It’s just an object with indexes and keys to denote the argument’s positions.

Methods like sort, map, forEach, or pop cannot be run on the arguments object. It also has other properties. This creates confusion for programmers.

The arguments that are converted to an array with the rest operator do not have these issues, as it is a real array.

To call the sum function we wrote, we can write:

const result = sum(1,2,3,4,5,6,7,8,9,10);

result will be 55, as we summed up all the arguments together. otherNums is an array with all the numbers other than 1 and 2.

We can also use the rest operator to destructure a list of arguments into a list of variables. This means that we can convert a list of parameters into an array with the spread operator, and then decompose the array of arguments into a list of variables.

This is very useful because we can get the entries of the array that’s operated on by the rest operator and convert them to named variables.

For example, we can write:

const sum = (a,b,...[c,d,e])=> a+b+c+d+e;

This way, we can use the rest operator but limit the number of arguments that your function accepts.

We take the function parameters a and b, and we also take c, d, and e as parameters. However, it’s probably clearer without using the rest operator as all the parameters are fixed, we can just list the parameters directly.


Conclusion

Now that we have the 2015 version of JavaScript, we can do many handy things with parameters.

Default values and the rest operator are handy for handling missing or operation parameters. Default parameters let us set default values for parameters that might not have anything passed in in function call arguments.

The rest operator lets us retrieve some or all items listed in the argument as an array. Letting us manipulate them with array operations or using the destructuring assignment to decompose them into individual variables.

Categories
JavaScript Basics

Spreading Arrays with JavaScript

The spread operator is one of the best recent JavaScript features.

In this article, we’ll look at what we can do with the spread operator.

Spread Operator

Rhe spread syntax lets us expand iterable objects like arrays and strings in various situations.

Merging Arrays

We can merge arrays with it.

For example, we can write:

const a = [1, 2, 3];
const b = [4, 5, 6];
const c = [...a, ...b[;

We put all the items from a and b into a new array and assign it to c .

So c is:

[1, 2, 3, 4, 5, 6]

Clone Array

Another way we can use it is to shallow copy an array.

For example, we can write:

const arr = [1, 2, 3];
const arrCopy = [...arr];

We made a copy with the spread operator. It expands the arr entries into a new array.

So arrCopy is also [1, 2, 3] .

But they reference different objects in memory.

Arguments to Array

The arguments object is an iterable object that has the arguments passed into a JavaScript function.

It’s only available in a traditional function.

For instance, we can write:

function foo() {
  const args = [...arguments];
  console.log(args);
}

args is an array.

So if we have:

foo(1, 2, 3)

Then args is [1, 2, 3] .

A more modern alternative that works with all functions is the rest operator:

const foo = (...args) => {
  console.log(args);
}

Then if we call it the same way:

foo(1, 2, 3)

args would have the same value.

String to Array

We can convert a string into an array of characters with the spread operator since string are iterable.

For example, we can write:

const string = 'hello world';
const array = [...string];

Then array is:

["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]

Set to Array

A set is an iterable object that can’t have duplicate entries.

Since it’s iterable, we can use the spread operator with it.

For example, we can write:

const set = new Set([1, 2, 2, 3, 3]);
const arr = [...set];

Then arr is [1, 2, 3] since the duplicates are removed from the set.

Map to Array

Maps are key-value pairs that’s stored in an object.

It’s also iterable so we can use the spread operator with it.

For example, we can write:

const map = new Map([
  ['foo', 1],
  ['bar', 2]
]);
const arr = [...map];

We spread the map with the operator and arr would be:

[
  ['foo', 1],
  ['bar', 2]
]

Node List to Array

Node lists are a list of DOM nodes.

It’s an iterable object but it’s not an array.

To convert them to an array, we can write:

const nodeList = document.querySelectorAll('div');
const nodeArr = [...nodeList];

We convert the node list returned from querySelectorAll to an array with the spread operator.

Conclusion

We can use the spread operator to spread or copy arrays and convert iterable objects to arrays.