Categories
JavaScript Basics

Handy JavaScript Array Tips

JavaScript, like any other programming language, has many handy tricks that let us write our programs more easily. In this article, we will look at how to do different things that involve arrays, like checking if an object is an array and combining arrays.

Check if an object is an Array

There are multiple ways to check if a JavaScript object or primitive value is an array. The newest way to check is to use the Array.isArray method. It takes one argument, which is any object or primitive value that we want to check if it’s an array. It returns true if it’s an array and false otherwise. However, for TypedArray objects like Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array, BigInt64Array, and BigUint64Array . It always returns false . For example, if we write the following code:

console.log(Array.isArray([1, 2, 3]));
console.log(Array.isArray(0));
console.log(Array.isArray(null));
console.log(Array.isArray({
  a: 1
}));
console.log(Array.isArray(undefined));
console.log(Array.isArray(Infinity));
console.log(Array.isArray(new Uint8Array()));

We get the following output from the console.log statements:

true
false
false
false
false
false
false

It’s a very handy method for determining if an object is an array. An alternative way to check if an object is an array is to use the instanceof operator. It works by checking if Array.prototype is on an object’s prototype chain. The only situation that it fails but works when using Array.isArray is that instanceof will fail when checking objects across frames wince the object instance will likely be different from the one that’s used for the array test with the instanceof operator. We can use it as in the following code:

console.log([1, 2, 3] instanceof Array);
console.log(0 instanceof Array);
console.log(null instanceof Array);
console.log({
    a: 1
  }
  instanceof Array);
console.log(undefined instanceof Array);
console.log(Infinity instanceof Array);
console.log(new Uint8Array() instanceof Array);

The console.log output should be exactly the same as the ones before since we didn’t put any objects inside a frame. Array.isArray is the simplest and most robust solution since most modern browsers have this method built-in, and that it works across frames.

Combining Arrays

With modern JavaScript, combining arrays into one is easier than ever. Array objects have the concat method which is called on an array, and takes in one or more arguments, which one or more arrays or objects that we want to combine into the array which it’s being called on. Note that it can also take in other non-array values that we want to pass in to be added into the array that it’s being called on. It returns a new array instance with the new array values so that we chain a series of calls to the concat method to combine more arrays into one. For example, we can write the following code for the most basic use case:

const arr1 = [1, 2, 3];
const arr2 = ['a', 'b', 'c'];
const combinedArr = arr1.concat(arr2);
console.log(combinedArr);

Then we get that the value of combinedArr will be [1, 2, 3, “a”, “b”, “c”] . We can also pass in more than one argument each of which are arrays into the concat method like in the following code:

const arr1 = [1, 2, 3];
const arr2 = ['a', 'b', 'c'];
const arr3 = ['1', '2', '3'];
const arr4 = ['d', 'e', 'f'];
const arr5 = ['g', 'h', 'i'];
const arr6 = [null, Infinity, NaN];
const arr7 = [10, 11, 12];
const arr8 = [{}, {
  a: 1
}, {
  b: 2
}];
const combinedArr = arr1.concat(arr2, arr3, arr4, arr5, arr6, arr7, arr8);
console.log(combinedArr);

Then we get the following output from the console.log output:

[
  1,
  2,
  3,
  "a",
  "b",
  "c",
  "1",
  "2",
  "3",
  "d",
  "e",
  "f",
  "g",
  "h",
  "i",
  null,
  null,
  null,
  10,
  11,
  12,
  {},
  {
    "a": 1
  },
  {
    "b": 2
  }
]

As we can see, the concat method is smart enough to combine multiple arrays into the first array, and that we have all the entries from all the arrays in one new array. The array returned from the concat method does not reference the original arrays. Also, it works with multiple types of data. It doesn’t matter what we pass in it, should still work. For example, if we have the following code:

const arr1 = [1, 2, 3];
const arr2 = ['a', 'b', 'c'];
const arr3 = ['1', '2', '3'];
const arr4 = ['d', 'e', 'f'];
const arr5 = ['g', 'h', 'i'];
const arr6 = [null, Infinity, NaN];
const arr7 = [10, 11, 12];
const arr8 = [{}, {
  a: 1
}, {
  b: 2
}];
const combinedArr = arr1.concat(arr2, arr3, arr4, arr5, arr6, arr7, arr8, 1, 'a', {
  c: 3
});

Then we get the following output if we run console.log on combinedArr :

[
  1,
  2,
  3,
  "a",
  "b",
  "c",
  "1",
  "2",
  "3",
  "d",
  "e",
  "f",
  "g",
  "h",
  "i",
  null,
  null,
  null,
  10,
  11,
  12,
  {},
  {
    "a": 1
  },
  {
    "b": 2
  },
  1,
  "a",
  {
    "c": 3
  }
]

This is very useful since don’t have to worry about the data types of the objects that we pass in or how many arguments we passed into the concat method. It takes as many arguments as we pass in. Since the concat method returns a new array with the values combined into one array, we can also chain the calls of the concat method to combine multiple things into a single array-like in the following code:

const arr1 = [1, 2, 3];
const arr2 = ['a', 'b', 'c'];
const arr3 = ['1', '2', '3'];
const arr4 = ['d', 'e', 'f'];
const arr5 = ['g', 'h', 'i'];
const arr6 = [null, Infinity, NaN];
const arr7 = [10, 11, 12];
const arr8 = [{}, {
  a: 1
}, {
  b: 2
}];
const combinedArr = arr1
  .concat(arr2)
  .concat(arr3)
  .concat(arr4)
  .concat(arr5)
  .concat(arr6)
  .concat(arr7)
  .concat(arr8)
  .concat(1)
  .concat('a', {
    c: 3
  });

Then we should get the following out when we run console.log on combinedArr :

[
  1,
  2,
  3,
  "a",
  "b",
  "c",
  "1",
  "2",
  "3",
  "d",
  "e",
  "f",
  "g",
  "h",
  "i",
  null,
  null,
  null,
  10,
  11,
  12,
  {},
  {
    "a": 1
  },
  {
    "b": 2
  },
  1,
  "a",
  {
    "c": 3
  }
]

With ES6, we have the spread operator, which we can use to combine arrays into one by spreading the values of the array into another array, and we can do that for all the arrays in one array separated by a comma after each array is spread. The spread also works with all array-like objects like arguments , Sets, Maps, or any object that has a Symbol.iterator method, which return a generator so that we can iterate through the items in the object with the for...of loop. To combine arrays and objects together into one array with the spread operator, we can write something like the following code:

const arr1 = [1, 2, 3];
const arr2 = ['a', 'b', 'c'];
const arr3 = ['1', '2', '3'];
const combinedArr = [...arr1, ...arr2, ...arr3];

Then we get:

[
  1,
  2,
  3,
  "a",
  "b",
  "c",
  "1",
  "2",
  "3"
]

when we run console.log on combinedArr . It also works with overlapping values across different arrays like the concat method does. For example, we can write the following code:

const arr1 = [1, 2, 3];
const arr2 = ['a', 'b', 'c'];
const arr3 = [1, '2', '3'];
const combinedArr = [...arr1, ...arr2, ...arr3];

and get that the value of combinedArr would be:

[
  1,
  2,
  3,
  "a",
  "b",
  "c",
  1,
  "2",
  "3"
]

As we can see, we have the value 1 in both arr1 and arr3 , but they both made it into combinedArr , which is good. We can also put objects into our new array that before, after or between the spread operations like in the following code:

const arr1 = [1, 2, 3];
const arr2 = ['a', 'b', 'c'];
const arr3 = [1, '2', '3'];
const combinedArr = ['c', ...arr1, 'c', ...arr2, 'c', ...arr3];

Then we get the following value for combinedArr :

[
  "c",
  1,
  2,
  3,
  "c",
  "a",
  "b",
  "c",
  "c",
  1,
  "2",
  "3"
]

This means that the feature of the concat method can easily be replicated by the spread operator, and we don’t have to pass in a long list of arguments or chain multiple calls of the concat method together to combine arrays and other types of objects into one array.

There are multiple ways to check if a JavaScript object or primitive value is an array. The newest way to check is to use the Array.isArray method, but we can also use the old instanceof operator to check if an object is an array. Array.isArray works across frames so it’s more robust than the instanceof operator. With modern JavaScript, combining arrays into one is easier than ever. Array objects have the concat method which is called on an array and takes in one or more arguments, which one or more arrays or objects that we want to combine into the array which it’s being called on. Note that it can also take in other non-array values that we want to pass in to be added into the array that it’s being called on. It returns a new array instance with all the combined values included in the new array.

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.