Introduction

So far, you have used variables to store singular values: a number, a boolean, a string, or even a function. But what if you want to store multiple values in a variable (e.g. 3 numbers, 5 strings, 2 numbers and 3 strings, etc.)? We can accomplish this with arrays.

An array is like a locker room. Each locker has a number, starting with 0. You can put anything into a locker. The locker number is called an index, and each locker is called an element (same name as a html element, but for different purposes/usage). The value of the element is the contents of the locker.

Please note that arrays in JavaScript are zero-based which means that JavaScript starts counting from zero when it indexes an array. The first element in an array has an index value of zero.

The following examples will show you how to create an array and access its data.

const trees = ['pine', 4, 'apple', 6, false, () => {}] // Example of an array.
let res = trees[0] // trees[0] refers to the element at index 0 in array trees,
// and the value of that element (which is "pine") is assigned
// to the variable res.
trees[4] = trees[0] + trees[2] // what is trees?
trees[5] = trees[1] + trees[3] // what is trees?
res = trees.length // res is 6. (total 6 elements)
// Like strings, arrays also have a special property called length.

You may notice that we are declaring the variable trees using const. This is intentional and it is not an error. The reason will be explained later in this chapter.

Answer
const trees = ['pine', 4, 'apple', 6, false, () => {}] // Example of an array.
let res = trees[0] // trees[0] will get the element at index 0, which is "pine"
trees[4] = trees[0] + trees[2] // ["pine", 4, "apple", 6, "pineapple", () => {}]
trees[5] = trees[1] + trees[3] // ["pine", 4, "apple", 6, "pineapple", 10]

Question from students:

  • trees went from

    ["pine", 4, "apple", 6, false, ()=>{}] to

    ["pine", 4, "apple", 6, "pineapple", () => {}].

    What happens to the false (element at index 4)?

    • = means left side takes the value of the right side. In other words, assign the value of the right side to the left side.
    a = 10
    a = 20
    // a is 20 because it took the value 20
    // in tech terms: assign 20 to variable a.

    trees[4] = 20 reads like this:

    the element at index 4 in array trees (left side) takes the value of 20 (right side)

Arrays can store any data, including other arrays and functions. Try to work through the comment questions in the below examples. They may look strange, but if you leverage the knowledge you already have, you should be able to work out the answers.

const barks = [
[1, 2, 3],
[2, 3, 4],
[3, 4, 5]
]
barks[2][1] = 10 // what is barks?
barks[1][0] = barks[2][1] // what is barks?
barks[2] = () => {
barks[0][1] = barks[0][1] + barks[0][0]
}
// what is barks?
barks[2]() // what is barks[2]()?
barks[1] = barks[2]()
// In the end, what is barks?
// fyi, barks is a 2-dimensional array
Answer
const barks = [
[1, 2, 3],
[2, 3, 4],
[3, 4, 5]
]
barks[2][1] = 10 // [[1,2,3], [2,3,4], [3,10,5]]
/*
The computer reads from left to right.
fyi: barks is a 2-dimensional array
barks[2] is the element at index 2 which has a value of array [3,4,5]
barks[2] refers to the 1st dimension and the element at index 2 which
is [3,4,5]
barks[2][1] -- [2] refers to the 1st dimension,
whereas [1] refers to the 2nd dimension.
barks[2][1] means
element at index 2 of 1st dimension and index 1 of 2nd dimension
which has a value of 4
const barks = [[1,2,3], [2,3,4], [3,***4***,5]]
barks[0] barks[1] barks[2] barks[2][1] has value of ***4***
So barks[2][1] = 10
means element at index 1 in array [3,***4***,5] takes the value 10
*/
barks[1][0] = barks[2][1] // [[1,2,3], [10,3,4], [3,10,5]]
// ^ ^
// barks[1][0] barks[2][1]
barks[2] = () => {
barks[0][1] = barks[0][1] + barks[0][0]
}
// the element at barks[2] has been replaced by a function
// barks now has [[1,3,3], [10,3,4], function]
barks[2]() // barks[2]() is undefined
barks[1] = barks[2]()
// barks now has [[1,4,3], undefined, function]

Although strings are similar to arrays because they both have a length property and you can use index to access data, it is important to note that strings are not arrays.

A string stores a series of characters like: comment = "The dog barks", whereas an array can store multiple values under the same variable name like: fruits = ["apples", "oranges", "pears"]

They are 2 different data types. Because of the way the underlying data is stored, there are things you can do to an array that you can't do to a string, and vice-versa.

Exercises

  1. Create an array with 3 identical strings.
Answer
const a = ['Thor', 'Thor', 'Thor']
  1. Create an array with 3 functions.
Answer
const b = [() => {}, () => {}, () => {}]
  1. Create an array with a string, a function, and an array.
Answer
const c = ['Peter', () => {}, [19, 'Quill']]
  1. Write a function named solution that takes in an array as a parameter and returns a function. When the returned function is called, the array input is returned.
Answer
const solution = input => {
return () => {
return input
}
}

Non-Primitive Data Types

In JS0 you learned that numbers, strings, and booleans are primitive data types. The value of a primitive data type variable can only contain a single thing (be it a string or a number or whatever).

// Primitive data types are known as being immutable data types
// because there is no way to change a primitive value once it gets created.
let string1 = 'This is a string.'
string1[1] = 'X'
console.log(string1) * //* string1 still has 'This is a string.'
// value of string1 cannot be changed
string1 = 'xyz'
console.log(string1) // string1 now has 'xyz'
// value of string1 has been totally replaced by 'xyz'
// here, a new copy of string1 is created with value 'xyz'
// and variable string1 gets reassigned to a new reference

All other data types are non-primitive data type.

For example, array is a non-primitive data type.

What this means is that when you assign an array to a variable, the variable stores an address (also known as a reference) to the actual array data, not the array data itself.

This concept actually exists in real life for the same reasons.

  • (primitive) - When someone gives you cash, you get the money itself.
  • (non-primitive) - When someone sells you their house, you get a deed with your name and the address of the house on it, and you also get the keys to the house. The deed states that you are the owner of the actual house.

In real life, we use addresses when dealing with houses because they are not easily portable. Similarly, addresses are needed for non-primitive data types because they tend to be large and therefore cannot move around easily. At work, it is very common for software engineers to work with arrays with thousands of elements.

Let's walk through a few examples.

const a = [1, 2, 3]
const b = [
false,
'spiderman',
(a, b) => {
return a - b
}
]

Let's dissect (step by step) what the computer would do when it sees the code above:

  • Line 1 = means that a is.... (need to figure out the right side)
    • The computer sees [1,2,3], so it goes into its memory and finds an empty place to store the data.
    • After the computer finds and stores the data, it no longer needs to keep track of the array. It simply keeps track of the location (address) of the data.
    • a contains the address or reference of the array.
  • Line 2
    • = means that b is.... (need to figure out the right side)
      • The computer sees [false,"spiderman",(a,b)=>{return a-b}], so it goes into its memory and finds an empty place to store the data. Note that this will be a different size space than the space used to store a.
      • After the computer finds and stores the data, it no longer needs to keep track of the array. It simply keeps track of the location (address) of the data.
      • b contains the address or reference of the array.

Note: In the above example, a and b have different addresses.

const a = [1, 2, 3]
const b = [1, 2, 3]
const c = a === b // what is c?
Answer
const a = [1, 2, 3]
const b = [1, 2, 3]
const c = a === b // false, because a and b have different addresses
// although they have the same content
const a = [1, 2, 3] === [1, 2, 3] // what is a?
Answer
const a = [1, 2, 3] === [1, 2, 3] // still false!
// the computer is creating 2 arrays and they have different addresses

Variable Declarations

const musicians = [1, 2, 3, 4] // Since arrays are non-primitive data,
// musicians contains the address to the musicians array data.
musicians[0] = 'Mozart' // did the variable musicians change?
musicians[1] = 'Beethoven' // did the variable musicians change?
musicians[2] = 'Liszt' // did the variable musicians change?
musicians[3] = 'Chopin' // did the variable musicians change?
Answer
const musicians = [1, 2, 3, 4] // Since arrays are non-primitive data,
// musicians is an address to the array data.
musicians[0] = 'Mozart' // no
musicians[1] = 'Beethoven' // no
musicians[2] = 'Liszt' // no
musicians[3] = 'Chopin' // no
// The data changed, but `musicians` itself contains an address.
// The address stayed the same.

For all non-primitive data, you should always declare them with a const because their address does not change.

When declaring non-primitive variables, only use let when you plan to reuse the variable to store other addresses. For example:

let musicians = ['Mozart', 'Beethoven']
musicians = ['Liszt', 'Chopin']
// musicians variable now holds a completely new address for a completely different array.

Variable Assignments

In many cases, software engineers introduce bugs into their codebase because they did not pay attention to the nature of non-primitive data types. The following examples will help you understand why you should be careful when working with non-primitive data.

const avengers = ['Banner', 'Stark', 'Odinson', 'Rogers']
const team = avengers
avengers[1] = 'Fury'
// what is avengers?
// what is team?
Answer
const avengers = ['Banner', 'Stark', 'Odinson', 'Rogers']
const team = avengers
avengers[1] = 'Fury'
// both avengers and team contain the same address or reference,
// so they both have the same values
// ["Banner", "Fury", "Odinson", "Rogers"]
const guardians = ['Rocket', 2, 'Drax']
const milano = guardians
milano[milano[1]] = 'Quill'
// What is guardians?
// What is milano?
Answer
const guardians = ['Rocket', 2, 'Drax']
const milano = guardians
milano[milano[1]] = 'Quill' // This is equivalent to: milano[2] = "Quill"
// guardians and milano contain the same address,
// so they both have the value
// ["Rocket", 2, "Quill"]
const planets = ['Morag', 'Aakon', 'Xandar']
const worlds = planets
worlds[2] = planets
worlds[2][1] = 'Ego' // What is worlds?
// What is planets?
Answer
const planets = ['Morag', 'Aakon', 'Xandar']
const worlds = planets // both worlds and planets have the same address
// to the same arrary
worlds[2] = planets // worlds[2] now stores the address to itself:
// ["Morag", "Aakon", worlds]
worlds[2][1] = 'Ego'
// worlds[2] is the address to worlds itself,
// which is the same address as planets
// Therefore, it's no different from writing planets[1] = "Ego"
// or worlds[1] = "Ego"
// both planets and worlds have:
// ["Morag", "Ego", worlds]
const planets = ['Morag', 'Aakon', 'Xandar']
let worlds = planets
worlds = ['Earth', 'Contraxia', 'Berhart']
// what is worlds?
// what is planets?
Answer
const planets = ['Morag', 'Aakon', 'Xandar']
let worlds = planets // worlds now has the same address as planets
worlds = ['Earth', 'Contraxia', 'Berhart'] // worlds is the address of a
// new array
// worlds: ["Earth", "Contraxia", "Berhart"]
// planets: ["Morag", "Aakon", "Xandar"]

Functions

We've seen several examples of how making assignments when working with non-primitive data can affect multiple variables. Our last example will look at what happens when an array is passed into a function. Run through the function like a computer would and figure out what's happening to each variable.

const fruitPrices = [100, 150, 200]
const addTax = (arr, i = 0) => {
if (i === arr.length) {
return arr
}
arr[i] = arr[i] * 1.1
return addTax(arr, i + 1)
}
const cost = addTax(fruitPrices) // what is cost?
// what is fruitPrices?
const isSame = fruitPrices === cost // what is isSame?
Answer
const fruitPrices = [100, 150, 200] // This is the only array that gets
// created in this code snippet!
const addTax = (arr, i = 0) => {
if (i === arr.length) {
return arr
}
arr[i] = arr[i] * 1.1
return addTax(arr, i + 1)
}
const cost = addTax(fruitPrices) // [110, 165, 220]
// fruitPrices is also [110, 165, 220] because they are the same array
const isSame = fruitPrices === cost // true, because they are the same array

Exercises

To keep your solutions organized, you can create a new file for this section (such as non-primitive.js) and a new test file (such as non-primitive.test.js). Refer back to Preflight if you need a refresher on the steps.

  1. Write a function named selectiveZero that takes in an array and a number. This function replaces the value of any elements of an array when the element's value matches the given number with a value of 0.

    selectiveZero([5, 2, 2, 9], 2) // [5,0,0,9]
Answer
  1. Tests

    describe('selectiveZero function', () => {
    it('should change multiple instances of the input number to 0', () => {
    const arr = [5, 2, 2, 9]
    fn.selectiveZero(arr, 2)
    expect(arr).toEqual([5, 0, 0, 9])
    })
    it('should return an empty array', () => {
    const arr = []
    const result = fn.selectiveZero(arr, 3)
    expect(result).toEqual(arr)
    })
    it('should not modify an array with no matches', () => {
    const arr = [8, 9, 1, "I'm a string"]
    const original = [...arr]
    fn.selectiveZero(arr, 6)
    expect(arr).toEqual(original)
    })
    })
  2. Shape

    const selectiveZero = (arr, val) => {}
  3. Explanation

    • You are given an array arr and a number val.
    • We need additional variable (let's say i ) to track index of an array which starts at 0.
    • When index i equals the length of array arr,
      • return arr.
    • When array arr at index i equals val,
      • update arr at that index i to equal 0.
    • Continue.
  4. Code

    const selectiveZero = (arr, val, i = 0) => {
    if (i === arr.length) {
    return arr
    }
    if (arr[i] === val) {
    arr[i] = 0
    }
    return selectiveZero(arr, val, i + 1)
    }
  1. Write a function named largest that returns the largest number in an array.

    largest([5, 3, 9]) // 9
    largest([-20, -2, -5, -10]) // -2
Answer
  1. Tests

    describe('largest function', () => {
    it('should find the largest of 3 numbers', () => {
    const result = fn.largest([5, 3, 9])
    expect(result).toEqual(9)
    })
    it('should find the largest of 4 negative numbers', () => {
    const result = fn.largest([-20, -2, -5, -10])
    expect(result).toEqual(-2)
    })
    it('should return undefined on an empty array', () => {
    expect(fn.largest([])).toEqual(undefined)
    })
    })
  2. Shape

    const largest = arr => {}
  3. Explanation

    • You are given an array arr .
    • We need additional variable (let's say i ) to track index of the array which starts at 0.
    • We need additional variable (let's say currentLargest ) to keep track of which values are largest at a given index which start at first index of arr.
    • When i equals the length of arr,
      • return currentLargest.
    • When the value of the element at index of i of array arr is greater than currentLargest,
      • Update currentLargest to the value of the element in array arr at index i.
    • Continue.
  4. Code

    const largest = (arr, i = 0, currentLargest = arr[0]) => {
    if (i === arr.length) {
    return currentLargest
    }
    if (arr[i] > currentLargest) {
    currentLargest = arr[i]
    }
    return largest(arr, i + 1, currentLargest)
    }
  1. Write a function named firstXToZero that sets the value of the first X elements in an array to 0, where X is the input number.

    firstXToZero([0, 5, 9, 6], 3) // [0,0,0,6]
    firstXToZero([1, 5, 4, 3, 3], 2) // [0,0,4,3,3]
    firstXToZero([1, 5, 9, 6], 1) // [0,5,9,6]
Answer
  1. Tests

    describe('firstXToZero function', () => {
    it('should change 3 numbers to 0', () => {
    const result = fn.firstXToZero([0, 5, 9, 6], 3)
    expect(result).toEqual([0, 0, 0, 6])
    })
    it('should not modify the array when changing 0 elements', () => {
    const result = fn.firstXToZero(["Don't", 'change', 'me'], 0)
    expect(result).toEqual(["Don't", 'change', 'me'])
    })
    it('should change all to zero when X beyond array length', () => {
    const result = fn.firstXToZero([1, 2, 3], 4)
    expect(result).toEqual([0, 0, 0])
    })
    })
  2. Shape

    const firstXtoZero = (arr, firstX) => {}
  3. Explanation

    • You are given an array arr and a number firstX.
    • We need additional variable (let's say i ) to track index of an array which starts at 0.
    • When index i equals the length of the array arr,
      • return array arr.
    • When index i is greater than or equal to number firstX,
      • return array arr.
    • Update the value of element at index i in array arr to 0.
    • Continue.
  4. Code

    const firstXToZero = (arr, firstX, i = 0) => {
    if (i === arr.length || i >= firstX) {
    return arr
    }
    arr[i] = 0
    return firstXToZero(arr, firstX, i + 1)
    }
  1. Write a function named allPrime that determines whether the value of every element in an array is a prime number.

    allPrime([2, 7, 9, 10]) // false, because 10 (2*5) is not prime
    allPrime([19, 13, 17, 11]) // true
Answer
  1. Tests

    describe('allPrime function', () => {
    it('should return true for an array of all primes', () => {
    const result = fn.allPrime([2, 3, 17, 19])
    expect(result).toEqual(true)
    })
    it('should return false for an array with some primes', () => {
    const result = fn.allPrime([0, 7, 11, 12])
    expect(result).toEqual(false)
    })
    it('should return true for an empty array', () => {
    const result = fn.allPrime([])
    expect(result).toEqual(true)
    })
    })
  2. Shape

    const allPrime = arr => {}
  3. Explanation

    • You are given an array arr.
    • We need additional variable (let's say i ) to track index of an array which starts at 0.
    • We need helper function isPrime to help us determine which element's value is prime in the given array arr.
    • When index i equals the length of array arr,
      • return true.
    • When the value of element at index i in array arr is not prime,
      • return false.
    • Continue
  4. Code

    const isPrime = (num, i = 2) => {
    if (num < i) return false
    if (num === i) return true
    if (num % i === 0) return false
    return isPrime(num, i + 1)
    }
    const allPrime = (arr, i = 0) => {
    if (i === arr.length) {
    return true
    }
    if (!isPrime(arr[i])) return false
    return allPrime(arr, i + 1)
    }
  1. Write a function named increasing that determines whether the elements of an array are ordered such that they represent a strictly ascending sequence of numbers. This means that the value of each element (other than the first) is greater than the value of the previous element.
Hint

This time you might not want to start your index counter at 0. Just remember if the array only has one element, your function should return true.

increasing([2, 7, 9, 10]) // true
increasing([19, 13, 17, 11]) // false, because 19 -> 13 is decreasing
increasing([2, 7, 7, 10]) // false. 7 -> 7 is technically not increasing
Answer

If you are asked this question during an interview, make sure to check with the interviewer what should happen if the input is an empty array! In this case, we choose to return true for empty arrays for convenience.

  1. Tests

    describe('increasing function', () => {
    it('should return true for an increasing array', () => {
    const result = fn.increasing([2, 7, 9, 10])
    expect(result).toEqual(true)
    })
    it('should return false for an array that decreases', () => {
    const result = fn.increasing([19, 13, 17, 11])
    expect(result).toEqual(false)
    })
    it('should return false if elements are repeated', () => {
    const result = fn.increasing([2, 7, 7, 10])
    expect(result).toEqual(false)
    })
    it('should return true for an array of one number', () => {
    const result = fn.increasing([51])
    expect(result).toEqual(true)
    })
    })
  2. Shape

    const increasing = arr => {}
  3. Explanation

    • You are given an array arr.
    • We need additional variable (let's say i ) to track index of an array which starts at 0.
    • When the index i is greater than or equal to the length of the array arr,
      • return true.
    • When the value of element at index i in array arr is less than or equal to the value of the element at previous index i - 1 in array arr
      • return false.
    • Continue.
  4. Code

    const increasing = (arr, i = 1) => {
    if (i >= arr.length) {
    return true
    }
    if (arr[i] <= arr[i - 1]) return false
    return increasing(arr, i + 1)
    }

Basic Array Functions

Now that you know how to create arrays and change the data inside the array, this section will show you the functions you need to run in order to add and remove data from an array.

Push()

The Push() method takes one or more elements as arguments and adds them to the end of an array. Push() returns the new length of the array.

const apples = ['Fuji', 'Gala']
const trees = apples.push('Pink Lady', 'Washington')
// apples is now ["Fuji", "Gala", "Pink Lady", "Washington"] because push adds
// to the array apples, trees now contains the new length of the array (4)
const peaches = [4, 8, 12]
const plums = peaches
peaches.push(plums)
// What is peaches?
// What is plums?
plums[0] = 47
// what is peaches?
// what is plums?
peaches[3][1] = 39
// what is peaches?
// what is plums?
let nectarines = [1, 2, 3]
nectarines = nectarines.push(6)
// what is nectarines?
Answer
const apples = ['Fuji', 'Gala']
const trees = apples.push('Pink Lady', 'Washington')
// apples is now ["Fuji", "Gala", "Pink Lady", "Washington"]
// because push adds to the array
// trees contains the new length of the array (4)
const peaches = [4, 8, 12]
const plums = peaches
peaches.push(plums)
// peaches and plums refer the same array (same address) and they are both have:
// [4, 8, 12, array]
// Note: [4, 8, 12, peaches] or [4,8,12,plums] are also both correct answers.
// we used array here to represent all of the possible answers:
// [4, 8, 12, peaches]
// [4, 8, 12, plums]
// [4, 8, 12, peaches[3]]
// [4, 8, 12, plums[3]]
// [4, 8, 12, plums[3][3]]
// [4, 8, 12, peaches[3][3]]
// [4, 8, 12, plums[3][3][3]]
// [4, 8, 12, peaches[3][3][3]]
// ...
plums[0] = 47
// peaches and plums are the same array (same address) and they are both:
// [47, 8, 12, array]
peaches[3][1] = 39
// peaches and plums are the same array (same address)
// peaches[3] also has the same address so peaches[3] is the same array as peaches
// [47, 39, 12, array]
let nectarines = [1, 2, 3]
nectarines = nectarines.push(6)
// push returns the length of the new array, so nectarines is 4

Pop()

Pop() method removes the last element in an array and returns the removed element.

If the array is empty, undefined is returned.

const states = ['Delaware', 'Missouri', 'Hawaii']
const lastState = states.pop()
// lastState is "Hawaii" and states is now ["Delaware", "Missouri"]
const nuts = ['almond', 'pistachio', 'hazelnut']
const seeds = nuts
const nutella = nuts.pop()
// What is nutella?
// What is nuts?
// What is seeds?
Answer
const states = ['Delaware', 'Missouri', 'Hawaii']
const lastState = states.pop() // "Hawaii"
// state is now ["Delaware", "Missouri"]
const nuts = ['almond', 'pistachio', 'hazelnut']
const seeds = nuts
const nutella = nuts.pop()
// nuts and seeds are the same array and they are both ["almond", "pistachio"]
// nutella is "hazelnut"

Shift()

Shift() is like pop() but in the opposite direction. It removes the first element in the array and returns the removed element. It returns undefined if the array is empty.

const states = ['Delaware', 'Missouri', 'Hawaii']
const firstState = states.shift()
// firstState is "Delaware" and states is now ["Missouri", "Hawaii"]
const nuts = ['almond', 'pistachio', 'hazelnut']
const seeds = nuts
const drupe = nuts.shift()
// What is nuts?
// What is seeds?
// What is drupe?
Answer
const states = ['Delaware', 'Missouri', 'Hawaii']
const firstState = states.shift()
// firstState is "Delaware" and states is now ["Missouri", "Hawaii"]
const nuts = ['almond', 'pistachio', 'hazelnut']
const seeds = nuts
const drupe = nuts.shift()
// nuts and seeds are the same array and they are both ["pistachio", "hazelnut"]
// drupe is "almond"

Unshift()

Unshift() is like push but in the opposite direction. It takes in one or more elements as arguments and adds them to the beginning of the array, and returns the new array length.

const nuts = ['almond', 'pistachio', 'hazelnut']
const seeds = nuts
nuts.unshift(seeds)
// What is nuts?
// What is seeds?
const states = ['Pennsylvania', 'New Jersey', 'Georgia']
const numStates = states.unshift('Delaware', 'New York')
// what is states and numStates?
Answer
const nuts = ['almond', 'pistachio', 'hazelnut']
const seeds = nuts
nuts.unshift(seeds)
// nuts and seeds are the same array (same address) and they are both:
// [array, "almond", "pistachio", "hazelnut"]
const states = ['Pennsylvania', 'New Jersey', 'Georgia']
const numStates = states.unshift('Delaware', 'New York')
// states is now ['Delaware', 'New York', 'Pennsylvania', 'New Jersey', 'Georgia']
// unshift returns the length of new array, so numStates is now 5

Splice()

The splice() method changes the contents of an array by removing or replacing existing elements and/or adding new elements in place.

The syntax of splice() is:

let arrDeletedItems = array.splice(start[, deleteCount[, item1[, item2[, ...]]]])

start

The index at which to start changing the array.

If start is greater than the length of the array, start will be set to the length of the array. In this case, no element will be deleted but the method will behave as an adding function, adding as many element as item[n*] provided.

If negative, it will begin that many elements from the end of the array. (In this case, the origin -1, meaning -*n* is the index of the nth last element, and is therefore equivalent to the index of array.length - *n*.)

If array.length + *start* is less than 0, it will begin from index 0.

deleteCount | Optional

An integer indicating the number of elements in the array to remove from start.

If deleteCount is omitted, or if its value is equal to or larger than array.length - *start* (that is, if it is equal to or greater than the number of elements left in the array, starting at start), then all the elements from start to the end of the array will be deleted.

Note: In IE8, it won't delete all when deleteCount is omitted.

If deleteCount is 0 or negative, no elements are removed. In this case, you should specify at least one new element (see below).

`item1item2, ...`  | Optional

The elements to be added to the array, beginning from index start. If you do not specify any elements, splice() will only remove elements from the array.

Return value

An array containing the deleted elements.

If only one element is removed, an array of one element is returned.

If no elements are removed, an empty array is returned.

Let's see some examples:

const fruits = ['Banana', 'Orange', 'Apple', 'Mango']
let removed = fruits.splice(2, 1, 'Lemon', 'Kiwi')
// First, 1 element is removed starting at index 2, so fruits becomes
// ["Banana", "Orange", "Mango"]
// Next, the rest of the parameters are added in at index 2
// Result: ["Banana", "Orange", "Lemon", "Kiwi", "Mango"]
const fruits2 = ['Banana', 'Orange', 'Apple', 'Mango']
removed = fruits2.splice(2, 2) // what is fruits2?
removed = fruits2.splice(0, 1, 'Apple', 'Mango', 'Pear')
// what is fruits2 and removed?
removed = fruits2.splice(-2, 1) // what is fruits2 and removed?
removed = fruits2.splice(1) // what is fruits2 and removed?
Answer
const fruits = ['Banana', 'Orange', 'Apple', 'Mango']
let removed = fruits.splice(2, 1, 'Lemon', 'Kiwi')
// First, 1 element is removed starting at index 2,
// so fruits becomes ["Banana", "Orange", "Mango"]
// Next, the rest of the parameters are added in at index 2
// fruits has ["Banana", "Orange", **"Lemon", "Kiwi",** "Mango"]
// removed has ["Apple"]
const fruits2 = ['Banana', 'Orange', 'Apple', 'Mango']
removed = fruits2.splice(2, 2)
// remove 2 elements starting at index 2 ("Apple", "Mango")
// fruits2 has ["Banana", "Orange"] (we didn't add anything)
// removed has ["Apple", "Mango"]
removed = fruits2.splice(0, 1, 'Apple', 'Mango', 'Pear')
// fruits2 was ["**Banana**", "Orange"]
// "Banana" at index 0 was removed,
// and "Apple", "Mango", "Pear" added at its place (index 0)
// fruits2 has ["Apple", "Mango", "Pear", "Orange"]
// removed has ["Banana"]
removed = fruits2.splice(-2, 1)
// fruits2 was ["Apple", "Mango", "**Pear**", "Orange"]
// remove 1 element, 2nd element from end which is "Pear"
// fruits2 has ["Apple", "Mango", "Orange"]
// removed has ["Pear"]
removed = fruits2.splice(1)
// fruits2 was ["Apple", "Mango", "Orange"]
// remove all element from index 1 onwards ("Mango", "Orange" removed)
// fruits2 has ["Apple"]
// removed has ["Mango", "Orange"]

Exercises

  1. Write a function named copyArray that takes in an array and returns a new array that is an identical copy of the given array.

    copyArray(['Rocket', 'Groot', 'Star-Lord']) // ["Rocket", "Groot", "Star-Lord"]
Answer
  1. Tests

    describe('copyArray function', () => {
    it('should copy an array of 3 elements', () => {
    const result = fn.copyArray([-5, -23, 'study'])
    expect(result).toEqual([-5, -23, 'study'])
    })
    it('should not modify original array', () => {
    const original = [
    'hi',
    1,
    () => {
    return 5
    },
    'apple',
    45
    ]
    const result = fn.copyArray(original)
    original[0] = 'Drax'
    expect(result[0]).toEqual('hi')
    })
    it('should copy an empty array', () => {
    const result = fn.copyArray([])
    expect(result).toEqual([])
    })
    })
  2. Shape

    const copyArray = a => {}
  3. Explanation

    • You are given an array a.

    • We will need another variable (let's say it is result ) to store the copy of the array and it starts at an empty array.

    • When the length of array result equals the length of array a,

      • return result.
    • Use the push() method with array result to push in the elements from array a .

      • Push all the elements from a to result.

      The push() method takes one or more elements as arguments and adds them to the end of an array. Push() returns the new length of the array.

    • Continue.

  4. Code

const copyArray = (a, result = []) => {
if (result.length === a.length) {
return result
}
result.push(a[result.length])
return copyArray(a, result)
}
Debrief
`push` was the most obvious choice for this task, because we could start out with an empty array and add all the elements to it. We could have also used `unshift` if we'd started from the end. In the next section, we'll learn a much easier way to copy arrays.
  1. Write a function named removeElement that takes in an array a and a string as parameters. This function removes any element of the array a when the element's value matches the value of the string. On completion, returns the updated array a.

    const a = ['Rocket', 'Groot', 'Groot', 'Star-Lord']
    const b = removeElement(a, 'Groot') // ["Rocket", "Star-Lord"]
    const c = b === a // since removeElement returns the original array,
    // b === a should be true
Hint

We haven't worked on removing array elements directly yet, but we did learn a function that can do the trick if you don't have any optional arguments...

Answer
  1. Tests

    describe('remove function', () => {
    it('should not remove anything', () => {
    const data = ['Rocket', 'Groot', 'Star-Lord']
    const result = fn.removeElement(data, 'Random')
    expect(result).toEqual(['Rocket', 'Groot', 'Star-Lord'])
    })
    it('should remove 1 element', () => {
    const data = ['Rocket', 'Groot', 'Star-Lord']
    const result = fn.removeElement(data, 'Star-Lord')
    expect(result).toEqual(['Rocket', 'Groot'])
    })
    it('should remove all elements', () => {
    const data = ['Rocket', 'Rocket', 'Rocket']
    const result = fn.removeElement(data, 'Rocket')
    expect(result).toEqual([])
    })
    })
  2. Shape

    const removeElement = (a, val) => {}
  3. Explanation

    • You are given an array a and a string val.

    • We need another variable (let's call it i) to keep track of index in array a. The index starts at 0.

    • When index i equals to the length of the array a,

      • return array a.
    • When the value of the element at index i in array a equals to the value of val, use splice to remove the element at index i in array a and then call removeElement function for the next element.

      The splice() method changes the contents of an array by removing or replacing existing elements and/or adding new elements in place.

    • Continue.

  4. Code

    const removeElement = (a, val, i = 0) => {
    if (i === a.length) {
    return a
    }
    if (a[i] === val) {
    a.splice(i, 1)
    return removeElement(a, val, i) // Should not do i+1
    // because array just became smaller
    }
    return removeElement(a, val, i + 1)
    }
Debrief

How is this different from the first exercise? Here we're not creating any new array, but rather modifying an existing one. So our recursive function only has to pass the address of the original array each time it's called.

In fact, because the function modifies its input, we could ignore the return value or not return anything at all. Changing the base case from return a to simply return and calling it with removeElement(a, "Groot") with no return variable would still modify a.

  1. Write a function named copyWithout that takes in an array and a number and returns a copied array. This function copies all elements in the array except for elements whose value matches the given number. On completion, returns the copied array.

    const result = copyWithout([5, 2, 2, 9], 2) // [5, 9]
Answer
  1. Tests

    describe('copyWithout function', () => {
    it('should copy without 2 middle elements', () => {
    const result = fn.copyWithout([5, 2, 2, 9], 2)
    expect(result).toEqual([5, 9])
    })
    it('should not modify original array', () => {
    const arr = [5, 2, 2, 9]
    fn.copyWithout(arr, 2)
    expect(arr).toEqual([5, 2, 2, 9])
    })
    it('should copy without last 2 elements', () => {
    const result = fn.copyWithout([2, 2, 2, 3, 3], 3)
    expect(result).toEqual([2, 2, 2])
    })
    it('should return identical array if no matches', () => {
    const result = fn.copyWithout([2, 6, 4], 3)
    expect(result).toEqual([2, 6, 4])
    })
    })
  2. Shape

    const copyWithout = (a, val) => {}
  3. Explanation

    • You are given an array a and a string val.
    • We need another variable (let's say it is i) to keep track of index in array a . The index starts at 0.
    • We need another array variable (let's say it is result) and it starts with empty array
    • When index i equals to the length of the array a,
      • return result .
    • When value of element at index i in array a is not equal to string val,
      • Push the element at index i in array a into the array result .
    • Continue with the next element in array a .
  4. Code

    const copyWithout = (a, val, i = 0, result = []) => {
    if (i === a.length) {
    return result
    }
    if (a[i] !== val) {
    result.push(a[i])
    }
    return copyWithout(a, val, i + 1, result)
    }
  1. Write a function named copyReverse that makes a copy of an array in the reverse order.

    copyReverse([5, 2, 2, 9]) // [9, 2, 2, 5]
Answer
  1. Tests

    describe('copyReverse function', () => {
    it('should reverse copy an array of 4 elements', () => {
    const result = fn.copyReverse([1, 3, 5, 7])
    expect(result).toEqual([7, 5, 3, 1])
    })
    it('should not modify original array', () => {
    const arr = [1, 3, 5, 7]
    fn.copyReverse(arr)
    expect(arr).toEqual([1, 3, 5, 7])
    })
    it('should reverse copy an array of 1 element', () => {
    const result = fn.copyReverse(['bears'])
    expect(result).toEqual(['bears'])
    })
    })
  2. Shape

    const copyReverse = a => {}
  3. Explanation

    • You are given an array a.

    • We need a variable (let's say it is result) to store a copy of array a backwards and it starts as an empty array.

    • When the length of array result equals length of array a ,

      • return result.
    • Use unshift method to copy all the elements of array a to an empty array result in reverse order. That is, start copying from the first element of array a to the beginning of array result , then copy the 2nd element of array a to the beginning of array result until all elements of array a have been copied.

      The unshift() method takes in one or more elements as arguments and adds them to the beginning of the array, and returns the new array length.

    • Continue

  4. Code

    const copyReverse = (a, result = []) => {
    if (result.length === a.length) {
    return result
    }
    result.unshift(a[result.length])
    return copyReverse(a, result)
    }
  1. Write a function named copyLast that copies an array but leaves out a given number of elements at the front.

    copyLast(['Ironman', 'Thor', 'Captain', 'Black Widow', 'Hulk'], 2)
    // ["Captain", "Black Widow", "Hulk"]
Answer
  1. Tests

    describe('copyLast function', () => {
    const heroes = ['Ironman', 'Thor', 'Captain', 'Black Widow', 'Hulk']
    const original = [...heroes]
    it('should skip the first 2 elements', () => {
    const result = fn.copyLast(heroes, 2)
    expect(result).toEqual(['Captain', 'Black Widow', 'Hulk'])
    })
    it('should not modify original array', () => {
    fn.copyLast(heroes, 2)
    expect(heroes).toEqual(original)
    })
    it('should skip the first 0 elements (copy whole array)', () => {
    const result = fn.copyLast(heroes, 0)
    expect(result).toEqual(heroes)
    })
    it('should return empty array if skipping past array length', () => {
    const result = fn.copyLast(heroes, 6)
    expect(result).toEqual([])
    })
    })
  2. Shape

    const copyLast = (a, b) => {}
  3. Explanation

    • You are given an array a and a number b as the inputs.

    • We need another variable (let's say result ) to store the new array which starts with an empty array "".

    • We need another variable (let's say it is i) to keep track of index in array a and it starts at 0

    • When index i is greater than or equal to the length of array a,

      • return result
    • When index i is greater than or equal to b,

      • get the element at index i in array a, and then push it into result.

      The push() method takes one or more arguments and adds them to the end of the array. Push() returns the new length of the array.

    • Continue

  4. Code

    const copyLast = (a, b, result = [], i = 0) => {
    if (i >= a.length) {
    return result
    }
    if (i >= b) {
    result.push(a[i])
    }
    return copyLast(a, b, result, i + 1)
    }
Debrief

We've been asked to skip the first certain number of elements in the array, so one easy way to do it is to start at the beginning and check each time if we've reached the starting point yet. We could also have set i=b as the default parameter.

The alternative solution without using the index variable i. The pushing starts from the value of number b, which is the number of elements to skip. Since index of array starts from 0, the index of the next element to push will be the same as the value of number b. The value of variable b will be incremented by 1 for the next element.

const copyLast = (a, b, result = []) => {
if (b >= a.length) {
return result
}
result.push(a[b])
return copyLast(a, b + 1, result)
}

The next exercise will challenge you to do the same type of modification, but on the other end of the array.

  1. Write a function called copyFirst that copies an array but leaves out a given number of elements at the end.

    copyFirst(['Ironman', 'Thor', 'Captain', 'Black Widow', 'Hulk'], 2)
    // ["Ironman", "Thor", "Captain"]
Answer
  1. Tests

    describe('copyFirst function', () => {
    const heroes = ['Ironman', 'Thor', 'Captain', 'Black Widow', 'Hulk']
    const original = [...heroes]
    it('should skip the last 2 elements', () => {
    const result = fn.copyFirst(heroes, 2)
    expect(result).toEqual(['Ironman', 'Thor', 'Captain'])
    })
    it('should not modify original array', () => {
    fn.copyFirst(heroes, 2)
    expect(heroes).toEqual(original)
    })
    it('should skip the last 0 elements (copy whole array)', () => {
    const result = fn.copyFirst(heroes, 0)
    expect(result).toEqual(heroes)
    })
    it('should return empty array if skipping past array length', () => {
    const result = fn.copyFirst(heroes, 6)
    expect(result).toEqual([])
    })
    })
  2. Shape

    const copyFirst = (a, b) => {}
  3. Explanation

    • You are given an array a and a number b.
    • We need an additional variable (let's say i) to keep track of index in array a and it starts at 0
    • We need another variable (let's say result ) which starts with an empty array "".
    • When index i is greater than or equal to a.length - b ,
      • return result
    • Push element at index i in array a into result.

    The push() method takes one or more elements as arguments and adds them to the end of an array. Push() returns the new length of the array.

    • Continue.
  4. Code

    const copyFirst = (a, b, result = [], i = 0) => {
    if (i >= a.length - b) {
    return result
    }
    result.push(a[i])
    return copyFirst(a, b, result, i + 1)
    }
  1. Write a function named runOnEach that calls a function on every element in an array, and returns a new array with the results.

    runOnEach([1, 2, 3, 4, 5], (e, i) => {
    // notice the input function has 2 parameters
    return e + i
    }) // returns [1, 3, 5, 7, 9]
Answer
  1. Tests

    describe('copyWithCall function', () => {
    const heroes = ['Ironman', 'Thor', 'Captain']
    const thanos = () => {
    return 'Thanos'
    }
    it('should call a function with two arguments', () => {
    const result = fn.runOnEach([1, 2, 3, 4, 5], (e, i) => {
    return e + i
    })
    expect(result).toEqual([1, 3, 5, 7, 9])
    })
    it('should not modify original array', () => {
    const original = [...heroes]
    fn.runOnEach(heroes, thanos)
    expect(heroes).toEqual(original)
    })
    it('should call a function with no arguments', () => {
    const result = fn.runOnEach(heroes, thanos)
    expect(result).toEqual(['Thanos', 'Thanos', 'Thanos'])
    })
    })
  2. Shape

    const runOnEach = (a, fn) => {}
  3. Explanation

    • You are given an array a and a function fn.
    • We need another variable (let's say it is i) to keep track of index in array a and it starts at 0
    • We need another variable (let's say result ) to store the new array and it starts with an empty array.
    • When index i equals to the length of array a,
      • return result.
    • Call the input function fn with element at index i in array a as one of the arguments.
    • Another argument for input function fn is index i.
    • Push the output of calling the input function fn into array result.
    • Continue.
  4. Code

const runOnEach = (a, fn, i = 0, result = []) => {
if (i === a.length) {
return result
}
result.push(fn(a[i], i))
return runOnEach(a, fn, i + 1, result)
}
Debrief

How did you do on that one? The main difference between this and exercise 1 is that here we're running the function on each element and its index. To work as expected, your function had to pass both the element and the index to the fn function—it's up to the called functions how many (if any) of their arguments they use.

  1. Write a function named onlyIndex that takes an array of arrays and returns an array of each array's element at a given index. (If you think of the big array as a table of rows, this function returns a given column).

    onlyIndex(
    [
    [1, 2, 3, 4, 5],
    [6, 9, 8, 7, 6],
    [4, 5, 6, 6, 7],
    [0, 1, 2, 3, 9]
    ],
    2
    ) // returns [ 3, 8, 6, 2 ]
Answer
  1. Tests

    describe('onlyIndex function', () => {
    const someNumbers = [
    [1, 2, 3, 4, 5],
    [6, 9, 8, 7, 6],
    [4, 5, 6, 6, 7],
    [0, 1, 2, 3, 4]
    ]
    it('should not modify the original array', () => {
    const original = [...someNumbers]
    fn.onlyIndex(someNumbers, 2)
    expect(someNumbers).toEqual(original)
    })
    it('should pull out the element at index 2', () => {
    const result = fn.onlyIndex(someNumbers, 2)
    expect(result).toEqual([3, 8, 6, 2])
    })
    it('should pull out the element at index 0', () => {
    const result = fn.onlyIndex(someNumbers, 0)
    expect(result).toEqual([1, 6, 4, 0])
    })
    })
  2. Shape

    const onlyIndex = (a, b) => {}
  3. Explanation

    • You are given an array of arrays a and a number b.

    • We need another variable (let's say it is i) to keep track of index in array a and it starts at 0.

    • We need another variable (let's say result ) to store the new array and it starts with an empty array "".

    • When index i is greater than or equal to the length of an array a,

      • return result
    • When number b is greater than or equal to the length of first index i of array a,

      • return result
    • Push array a at index i and number b into array result.

    • Continue.

  4. Code

    const onlyIndex = (a, b, i = 0, result = []) => {
    if (i >= a.length) {
    return result
    }
    if (b >= a[0].length) {
    return result
    }
    result.push(a[i][b])
    return onlyIndex(a, b, i + 1, result)
    }
Master your skill by solving challenges

Complete the first six JS2 challenges

Edit this page on Github