JavaScript Course 5: Arrays
References
- Code with Mosh: The Ultimate JavaScript Mastery Series – Part 1
- W3School: JavaScript Tutorial
- W3School: JavaScript Array Reference
See also:
Declaring an Array
const numbers = [3, 4]; // Array Literal
typeof numbers; // "object"
Constant does not stop us from modifying the content of an Array, we can adding and remove elements. Just we can't reassign the variable to different type.
In JavaScript, the Arrays are kind of objects, so the are a couple of built-in properties [like .length
] and methods [like .indexOf()
].
Remember the index of the Arrays starts from 0
.
[1, 2, 3, 1, 4]
0 1 2 3 4
Adding Elements to an Array
Add elements to the end of an Array by using .push(elements)
method. It adds new items to the end of an array, changes the length of the array, returns the new length.
numbers.push(5, 6);
console.log(numbers);
(4) [3, 4, 5, 6]
Add elements to the beginning of an Array by using .unshift(elements)
method. It adds new elements to the beginning of an array, overwrites the original array.
numbers.unshift(1, 2);
console.log(numbers);
(6) [1, 2, 3, 4, 5, 6]
Add elements to the middle of an Array by using .splice(index, delete count, elements to add)
method. It adds and/or removes array elements, overwrites the original array.
numbers.splice(2, 0, 'a', 'b'); // 0 means we won't remove elements
console.log(numbers);
(8) [1, 2, 'a', 'b', 3, 4, 5, 6]
Finding Elements in an Array
Finding Primitive types in an Array
const numbers = [1, 2, 3, 1, 4];
By using .indexOf(element, start_index=0)
method we can find the first occurrence of an element.
console.log(numbers.indexOf(1));
0
console.log(numbers.indexOf(3));
2
console.log(numbers.indexOf('c')); // This element doesn't exist
-1
By using .lastIndexOf(element, start_index=array_lenght)
method we can find the last occurrence of an element.
console.log(numbers.latIndexOf(1));
3
Test whether a given (primitive) element exists in an Array
const numbers = [1, 2, 3, 1, 4];
The old way, by using .indexOf(element, start_index=0)
method.
console.log(numbers.indexOf(1) !== -1); // will return 'true' if one or more elements with value 1 exist in the array 'numbers'
if (numbers.indexOf(1) !== -1) { ... }
The modern way, by using .includes(element, start_index=0)
method.
console.log(numbers.includes(1)); // will return 'true' if one or more elements with value 1 exist in the array 'numbers'
if (numbers.includes(1)) { ... }
Start Index
All these methods ah a second optional parameter which is start index
.
const numbers = [1, 2, 3, 1, 4, 1, 5, 6];
console.log(numbers.length);
8
console.log(numbers.indexOf(1)); // start index = 0
0
console.log(numbers.indexOf(1, 2)); // start index = 2
3
console.log(numbers.lastIndexOf(1)); // start index = array_length, and backwods count
5
console.log(numbers.lastIndexOf(1, 4)); // start index = 4, and backwods count
3
Finding Reference types in an Array
const courses = [
{id: 1, name: 'a'},
{id: 2, name: 'b'}
];
By using .find(callback_fn)
method we can find an Object within Array, which has a given property.
let course_A_exist = courses.find(function(course) {
return course.name === 'a';
});
console.log(course_A_exist); // will return 'undefined' if the element dosn't exist
{id: 1, name: 'a'}
By using .findIndex(callback_fn)
method we can find the Index of an Object within Array, which has a given property.
let course_B_index = courses.findIndex(function(course) {
return course.name === 'b';
});
console.log(course_B_index); // will return '-1' if the element dosn't exist
1
Arrow Functions
Here is how to transform the above callback function to an Arrow function.
The initial state of the callback function.
let course_A_exist = courses.find(function(course) {
return course.name === 'a';
});
Step 1, remove the function keyword, and separate the parameters of the function from its body put a fat arrow.
let course_A_exist = courses.find((course) => {
return course.name === 'a';
});
Step 2, if the function have a single parameter we can also remove the parentheses.
let course_A_exist = courses.find(course => {
return course.name === 'a';
});
If you do not have any parameters you have to pass empty parentheses:
let course_A_exist = courses.find(() => { ... });
Step 3, if the function is a single line of code, we can make this code even shorter: 1) get rid of the return
keyword, 2) remove the curly braces, 3) place everything on one line.
let course_A_exist = courses.find(course => course.name === 'a');
Removing Elements of an Array
const numbers = [1, 2, 3, 4, 5, 6];
Remove elements to the end of an Array by using .pop(elements)
method. It removes (pops) the last element of an array, changes the original array, returns the removed element.
let last = numbers.pop();
console.log(numbers);
(5) [1, 2, 3, 4, 5]
console.log(last);
6
Remove elements to the beginning of an Array by using .shift(elements)
method. It removes the first item of an array, changes the original array, returns the shifted element.
let first = numbers.shift();
console.log(numbers);
(4) [2, 3, 4, 5]
console.log(first);
1
Remove elements to the middle of an Array by using .splice(index, delete count, elements to add)
method. It adds and/or removes array elements, overwrites the original array.
numbers.splice(1, 2); // we will remove 2 elemets starting from index 1
console.log(numbers);
(2) [2, 5]
Emptying an Array
1. Reassign to a new empty array. In this case we can't use const
in order to define the array's memory object.
let numbers = [1, 2, 3, 4, 5, 6];
numbers = [];
console.log(numbers);
[]
Note, the old array exists as an object in the memory and if it is not used anymore, it will be handled by the garbage collector. But if we have its reference we sill able to see and use it.
let numbers = [1, 2, 3, 4, 5, 6];
let another = numbers;
numbers = [];
console.log(numbers);
[]
console.log(another);
(6) [1, 2, 3, 4, 5, 6]
So the above solution works if do not have references to the original array. Otherwise if you do have multiple references to the original array an you want to change (empty) this array you have to use a different solution.
2. Change the array .length
property to 0
. In this case we can use const
in order to define the array memory object. This is the best solution!
const numbers = [1, 2, 3, 4, 5, 6];
const another = numbers;
numbers.length = 0;
console.log(numbers, another);
[] []
3. Use the .splice()
method. In this case we can use const
in order to define the array memory object.
const numbers = [1, 2, 3, 4, 5, 6];
const another = numbers;
numbers.splice(0, numbers.length);
console.log(numbers, another);
[] []
4. Use the .pop()
method and a loop. In this case we can use const
in order to define the array memory object. This is not recommended, performance cost solution.
const numbers = [1, 2, 3, 4, 5, 6];
const another = numbers;
while (numbers.length > 0) numbers.pop();
console.log(numbers, another);
[] []
Combining and Slicing Arrays
Combining Arrays
To combine these Arrays we can use the .concat(array)
method.
const first = [1, 2, 3];
const second = [4, 5, 6];
const combined = first.concat(second);
console.log(combined);
(6) [1, 2, 3, 4, 5, 6]
Slicing an Array
const combined = [1, 2, 3, 4, 5, 6];
In order do slice an Array we can use the .slice(start index, end index)
method.
const slice1 = combined.slice(2, 4);
console.log(slice1);
(2) [3, 4]
We can use also only the start index
.
const slice2 = combined.slice(3);
console.log(slice2);
(3) [4, 5, 6]
If we omit also the start index we can create a copy of the array by this method.
const copy = combined.slice();
console.log(copy);
(6) [1, 2, 3, 4, 5, 6]
Reference types
The above methods – .slice()
and .concat()
– are dealing with Primitive types. If we have Reference types in an Array these methods will not copy the referred objects, but only the references to them.
const first = [{id: 1}, {id: 2}];
const second = [4, 5, 6];
const combined = first.concat(second);
first[0].id = 888;
console.log(combined);
(5) [{id: 888}, {id: 2}, 4, 5, 6]
The Spread Operator
const first = [1, 2, 3];
const second = [4, 5, 6];
In ES6 we can use the Spread operator – ...spread
– to achieve the same result as the .concat()
method from the above section. The Spread operator approach is cleaner and more flexible.
const combined1 = [...first, ...second];
console.log(combined1);
(6) [1, 2, 3, 4, 5, 6]
By using the Spread method we can add elements in a way as it is shown below.
const combined2 = ['at the beginning', ...first, 'in the middle', ...second, 'at the end'];
console.log(combined2);
(9) ['at the beginning', 1, 2, 3, 'in the middle', 4, 5, 6, 'at the end']
We can use the Spread operator also in order to copy an array.
const copyOfFirst = [...first];
console.log(copyOfFirst);
(3) [1, 2, 3]
The spread operator also dealing only with Promotive types and just copies the references of Reference types.
Iterating an Array
const numbers = [1, 2, 3];
Use for.. of..
loop.
for (let number in numbers) console.log(number);
1
2
3
Use .forEach(calback_f)
method.
numbers.forEach(function(number) { console.log(number) });
1
2
3
numbers.forEach(number => console.log(number));
1
2
3
The loopback function can have second parameter, which is index
.
numbers.forEach((element, index) => console.log(index, element));
0 1
1 2
2 3
Joining an Array and Splitting a String
The .join('optional field separator')
method could be used to convert an Array into string.
const numbers = [1, 2, 3, 4, 5, 6];
const joined = numbers.join('-');
console.log(joined);
1-2-3-4-5-6
We can use the .split('field separator')
method (that belongs to the String objects) in order to convert a String to an Array.
const text = 'This is the message';
const array = text.split(' ');
console.log(array);
(4) ['This', 'is', 'the', 'message']
Sorting and Reverse Arrays
Primitive types
const numbers = [2, 3, 1];
Use .sort()
method. It sorts the elements of an array, overwrites the original array, sorts the elements as strings in alphabetical and ascending order.
numbers.sort();
console.log(numbers);
(3) [1, 2, 3]
Use .reverse()
method. The array after it has been reversed.
numbers.reverse();
console.log(numbers);
(3) [3, 2, 1]
Reference types
const numbers = [
{id: 1, name: 'Node.js'}, // When sorting by name this should be Third
{id: 3, name: 'C++'}, // When sorting by name this should be First
{id: 2, name: 'JavaScript'} // When sorting by name this should be Second
];
Use .sort(callback_fn)
method. There the sorting will be dove via ASCII order, reference: https://www.asciitable.com/
numbers.sort(function(a, b) {
// Remove case sensitivity
const nameA = a.name.toLowerCase(); // .toUpperCase() is also valid,
const nameB = b.name.toLowerCase(); // but both should be equal
if (nameA < nameB) return -1;
if (nameA > nameB) return 1;
return 0;
});
console.log(numbers);
(3) [{id: 3, name: 'C++'}, {id: 2, name: 'JavaScript'}, {id: 1, name: 'Node.js'}]
Testing the Elements of an Array
const numbers = [2, 3, 1];
Use .every(callback_fn)
method. It executes a function for each array element, returns true
if the function returns true for all elements, returns false
if the function returns false for one element, does not execute the function for empty elements, does not change the original array. Available in ES6+.
let areAllPositive = numbers.every(function(value) {
return value >= 0;
});
console.log(areAllPositive);
true
numbers[3] = -2;
areAllPositive = numbers.every(value => value >= 0);
console.log(areAllPositive);
false
Use .some(callback_fn)
method. It checks if any array elements pass a test (provided as a function); executes the function once for each array element: 1) If the function returns true, some() returns true and stops, 2) If the function returns false, some() returns false and stops; does not execute the function for empty array elements; does not change the original array.
let atLeastOneNegative = numbers.some(function(value) {
return value < 0;
});
console.log(atLeastOnePositive);
true
numbers.pop();
atLeastOneNegative = numbers.some(value => value < 0);
console.log(atLeastOneNegative);
false
Filtering an Array
const numbers = [2, -1, 3, -7, 1, 5];
Use .filter(callback_fn)
in order to filter an array based on a search criteria. It creates a new array filled with elements that pass a test provided by a function, does not execute the function for empty elements, does not change the original array.
In the next example we will filter only the positive values. And in addition will sort them in a reverse order.
let onlyPositive = numbers.filter(function(value) {
return value >= 0;
}).sort().reverse();
- Better practice is to put chaining methods on a new line.
console.log(onlyPositive);
(4) [5, 3, 2, 1]
Mapping an Array
const items = ['item 1', 'item 2', 'item 3'];
With the .map(callback_fn)
method we can map each element in an Array to something else. It creates a new array from calling a function for every array element, calls a function once for each element in an array, does not execute the function for empty elements, does not change the original array.
const itemsList = '<ul>' + items.map(item => '<li>' + item + '</li>').join('') + '</ul>'; // Note ',' is the default joining separator of .join()
console.log(itemsList);
<ul><li>item 1</li><li>item 2</li><li>item 3</li></ul>
Convert an Array of Primitives into an Array of References
This approach should be available with all kind of (callback) functions – here we will use the .map()
method.
const numbers = [1, 2, 3];
Using a Standard function and explicit syntax.
const items = numbers.map(function(n) {
const obj = {'value': n};
return obj;
});
Using a Standard function and short syntax.
const items = numbers.map(function(n) {
return {'value': n};
});
Using an Arrow function. Note in this case we need to enclose the output object in parenthesis, because in otherwise the JavaScript engine will threat the curly braces as code block.
const items = numbers.map(n => ({'value': n}) );
The output of the three examples is the same.
console.log(items);
(3) [{value: '1'}, {value: '2'}, {value: '3'}]
Reducing an Array
const numbers = [1, -1, 2, 3];
Using for.. of..
loop – the old way.
let sum = 0;
for (let n of numbers) sum += n;
console.log(sum);
5
Using .reduce(function(total, currentValue, currentIndex, arr), initialValue)
method of the array objects. It executes a reducer function for array element, returns a single value: the function's accumulated result, does not execute the function for empty array elements, does not change the original array.
let sum = numbers.reduce(function(accumulator, currentValue) {
return accumulator + currentValue;
}, 0); // accumulator = 0; if we omit this value the 'accumulator' will be initialized with the value of the firs element
Or as Arrow function and without initalValue
for the total
.
let sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue);
console.log(sum);
5