Quite often in programming, we need to deal with numerous elements at once. Let's say we have a list of test scores and we want to calculate the average score. In JavaScript, we would use an array to store the score:
const array = [70, 80 , 65, 100, 90, 95];
Then we would be able to loop over the array, summing together each test score:
let total = 0;
for(let i=0; i<array.length; i++){
total +=array[i];
}
Once we have a total sum of test scores, we can simply divide it by the array length (the number of tests in our population), to get our average score:
const average = total / array.length;
Having the knowledge to easily store multiple elements, use an index to retrieve an element, and quickly retrieve the total length of the elements are hallmarks of what makes arrays so valuable.
Let's dive into the syntax some more and work on some exercises with arrays!
Arrays
In JavaScript, when we want to store a list of elements we use an Array.
An array starts with an open square bracket "[" and ends with a closed square bracket "]". The elements inside the array are separated by a comma ",". Here are some examples of arrays filled with primary types:
const numbers = [1, 2, 3, 4, 5];
const booleans = [true, false, true, true];
const strings = ["happy", "go", "lucky"];
We can also store arrays within arrays! Referred to as a nested array.
const nested = [[1, 2,[1, 2]],2];
In this example, the top-level nested array has two elements: an array [1, 2, [1, 2]] and element 2.
Array Indexing
Just like strings, arrays have zero-based indexes. This means that the first element in the array is at index 0, then 1, then 2:
We can retrieve an element in an array by putting an index in square brackets []:
const element = array[0];
This makes it quite easy to loop over an array using an index starting from 0 and moving to the array's length:
const arr = ['h', 'a', 'p', 'p', 'y'];
for (let i=0; i< arr.length; i++){
console.log(arr[i]);
}
This will log h, a, p, p, y as the index i move from 0 to 4.
Equivalent to strings, arrays also have a length method on the array prototype. This method returns a count of the number of items within the array.
In JavaScript, you can return early in a function which may make this easier than returning in a single spot.
Return Early
In JavaScript there are often situations when you want to return true or false depending on whether an element from a list of elements matches some condition.
Cosider a situation where we want to know if all numbers are less than 10:
function lessThanTen(array){ let allLessThanTen = true; for(let i=0; i<array.length; i++){ if(array[i]>=10){ allLessThanTen = false; break; } } return allLessThanTen; }
The above code will work just fine! We are creating a boolean allLessThanTen that assumes true unless we find some element that is greater than or equal to 10 within our array.
There may be a simpler way to do this though!
function lessThanTen(array){ for(let i=0; i<array.length; i++){ if(array[i]>=10){ return false; } } return true; }
This code accomplishes the same thing as the code above it, yet in fewer lined! Notice we hae two return statements. The return false will only ever occur if an element is found to match the condition.
Choosing whether you want to keep a boolean or return early is up to you. Whatever makes the code simplest and easy to read!
Running Value
We can keep a running value while we're looping over an array. There are many reasons we might do this. For instance, if we wanted to find the average of many numbers like:
const result = average([80,90,98,100]);
console.log(result);//92
The average function will want to loop over the array and keep a running total of the values. Then it will divide by the length of the array to find the average:
function average(array){
let total = 0;
for(let i=0; i<array.length; i++){
total +=array[i];
}
return (total/array.length);
}
There are a few different ways we could handle writing this function. In a future lesson, this would be a good candidate for the Array Reduce!
The reduce() method executes a user-supplied "reducer" callback function on each element of the array, in order, passing in the return value fro the calculation on the preceding element. The final result of reuuing the reducer across all elements of the array is a single value.
The first time that the callback is run there is no "return value of the previous calculation". If supplied, an initial value may be used in its place. Otherwise the array element at index 0 is used as the initial value and iteration starts from the next elment (index 1 instead of index 0).
Perhaps the easiest-to-understand case for reduce() is to return the sum of all the element in an array:
const array1 = [1, 2, 3, 4]; const initialvalue = 0; const sumWithInitial = array1.reduce(accumulator, currentValue) => accumulator + currentValue, initialValue); console.log(sumWithInitial);//Wxpected output: 10
The reducer walks through the array element-by-element, at each step adding the current array value to the result from the previous step (this result is the running sum of all the previous steps) -- until there are no more elements to add.
When to not use reduce()
Recursive function like reduce() can be poserfull but sometimes difficult to understand, especially for less-experienced JavaScript developers. If code becomes clearer when using other array methods, developer must weigh the readablity tradeoff against the other benefits of using reduce(). In cases where reduce() is the best choice, documentation and semantic variable naming can help mitigate readability drawbacks.
don't worry if you don't understand some of the terms you will be able to understand these futher lessons until then don't loose momentum.
-reduceRight()
The reduceRight() method applies a function against an accumulator and eacah value of the array (from right-to left) to reduce it to a single value. This method comes in pretty handy when you want to specify items in a left-to-right manner but execute them in a right-to-left manner.
You could use reduceRight() method to replace
array.reverse().reduce()
const number = [[0,0],[1,1],[2,2]]; const modifiedNumber = number.reduceRight((a,b)=>a.concat(b)); console.log(modifiedNumbers); //[2,2,1,1,0,0]
Returning a New Array
When writing a function to filter an array, we can create a new array and push the elements into that new array when they satisfy our condition.
Let's say we want to filter an array to return only numbers greater than 5:
function greaterThanFive(array){
const newArray = [];
for(let i=0; i<array;length; i++){
const element = array[i];
//is this element greater than 5?
if(element > 5){
//yes, push this element on our array
newArray.push(element);
}
}
return newArray;
}
In this case, we're creating a new array and then using elements from the array onto our newArray only if they are greater than 5. Lastly, we return the new array.
The push() method appends values to an array.
The push() method is a mutating method. It changes the length and the content of this . The push() method is generic. It only expects the this value to have a length property and integer-keyed properties. Although strings are also array-like, this method is not suitable to be applied on them, as strings are immutable.
Let's examine how to determine if an element is contained in array.
Contains Element
How do we determine if an element already exists inside an array?
In the strings tutorial we discussed the indexOf method . This method also exist on arrays!
Let's say we had an existing array and wanted to know if an element is contained in it:
const element = 3; const array = [1, 2, 3]; cosnt isContained = array.indexOf(element)>=0; console.log(isContained);//true
If the array does not contain the element, the indexOf method will return -1. Therefore, if the index returned is greater or equal to zero we know it is contained.
The variable isContained in this case will be true because it contains 3 ! So how do we apply this to unique numbers?
Similar to our greaterThanFive example in the task, we can start by creating a new array. We can then choose to add all numbers to this new array so long as they are not already contained.
-lastIndexOf()
The lastIndexOf() method returns the last index at which a given element can be found in the array, or -1 if it is not present. The array is searched backwards, starting at fromIndex if this argument is available. The lastIndexOf() method is case-sensitive.
const names = ['John', 'Bolanle', 'Dwight', 'Marry']; console.log(nemes.lastIndexOf('Dwight')); //2 //-1 is returned if the searchValue is absent in the array console.log(names.lastIndexOf('Tiger')); //-1
Modifying Array Values
We have learned to read from array values using square brackets such as array[0].
Likewise, we can write new values to those positions using the assignment operator =.
const array = [1, 2, 3];
array[0] = 5;
console.log(array);//[5, 2, 3]
We changed the element in the 0 indexes of the array by using the assignment operator
Notice how this example uses const, and yet, we were still able to change the value! For objects and arrays, const only protects from changing the reference.
Reference
When storing an object in a variable we are storing a reference to the object. You can think of it as a lookup for the value (not the value itself).
This is tough to explain, so maby a couple examples will help!
let a = 3; let b = a;
So far both a and b are 3. What if we changed a?
a = 10; console.log(a);//10 console.log(b);//3
Notice how a changed to 10 and b stayed 3. This is an important point!
When we assign b = a we are assigning the value inside a to b. This does not link a with b in any way. It simply copies the value 3 into b. This is how assignment works with all primitive values.
Contrarily, with objects we assign by reference. Let's see an example:
let a = [1, 2, 3]; let b = a;
Now b also stores [1, 2, 3]. What if we changed the first element in a?
a[0] = 5; console.log(a);//[5, 2, 3] console.log(b);//[5, 2, 3]
Ah, look b also changed! This is because b stores a reference to the same rray that a stores a reference to.
Take a moment and think about how this would differ from primitive values. In the first example with number we changed a and that did not change b.
When we use the word const with an array or an object, JavaScript does not care whether we change a value inside of the data structure.
An important thing to note: arrays are objects. So when we talk about properties of an object, you can extend those to arrays as well.
Be awere that const keyword will stop us from changing the reference!
const arr = [1, 2, 3]; arr[0] = 5;
This is okey!
const arr = [1, 2, 3]; arr = [5, 6, 7];
This is no good. JavaScript will throw a TypeError: Assignment to constant variable.
Modifying the Array
Let's filter an array by modifying it directly!
We'll need a method to remove elements from an array. Luckily, we have such a method. It's called splice!
Let's remove any element greater than five from our array:
function greaterThanFive(array){
for(let i=array.length; i>=0; i--){
if(array[i]<=5){
array.splice(i,1);
}
}
}
We're using the splice function with two arguments.
The first argument is the starting index where we'd like to start the removal of elements.
The second argument is the number of elements we'd like to remove
Beginning at the starting index. In this case, we're removing a single element starting at the index of the element we'd like to remove.
Wondering why we're counting down in the for loop? Let's see how splice can affect our index.
Splice Index
Let's use splice to remove element that are greater than 1:
const array = [1, 2, 3]; for(let i=0; i<array.length; i++){ if(array[i]>1){ array.splice(i,1); } } console.log(array);//[1,3]
Uh-oh, A bug!
Why is the console.log showing that array contains 1 and 3 ?
We should be splicing any elements that are greater than 1. Why is 3 still in our array?
Let's break it down by iteration:
Iteration 1
The first iteration works as expected! The index points at the element 1.
We do not splice 1 because it is not greater than 1 .
Iteration 2
The second iteration also works as expected!
We find that 2 is greater than 1 so we splice at index 1
Last iteration ?
Huh. Our array length is 2 and i is 2 .
Uh-oh! Our loop condition is that i<array.length, so there are no futher iterations at this point. We never removed 3!
How can we fix this
Counting Backwords
Let's try this again counting backwords:
const array = [1, 2, 3]; for(let i=array.length; i>=0; i--){ if(array[i]>1){ array.splice(i,1); } } console.log(array);//[1]
Sweet! it works as expected!
Let's take a look at the iterations.
Iteration 1
Good so far! We point at the 3 because we ae starting at the end of the array.
We remove 3 because it is greater than 1.
Iteration 2.
This looks good again!
We moved the index i down by 1 and we found that 2 should alos be removed. We successfully splice it at the index 1.
Iteration 3
Good again! 1 is not greater than 1, so we don not splice it.
We are left with [1] in our array, just like we expected!
counting backword for the win!
So far we've learned so many things in JavaScript next we will discuss objects in JavaScript How to create them and why we need them till then keep learning.