No site found for btvca-curriculum.herokuapp.com; using Bootcamp content.

Array Properties and Methods

Every JavaScript Array is also a JavaScript Object

That means that arrays have properties and methods like other objects.

Examples:

let myArray = ['apple', 'cherry', 'pineapple'];
  • myArray.length is a property that is the number of elements in the array
  • myArray.reverse() is a method that reverses the ordering of all elements in the array

NOTE: Properties are called by their name alone, but Methods require parenthesis () after the name

See MDN: Array Methods to see a lot more array methods

Iteration Methods

Every JavaScript array has many tools that let you pass each item to a function to its contents.

method name description returns
forEach do something with each item undefined
find find the first item matching the test one matching item (or undefined if no match)
filter accept or reject each item a new Array of matching items
map change each item into a new item a new Array of the same size
reduce scan the entire collection and "reduce" it to... ...a single result, e.g. a total
  • We call this group of methods "iteration methods"
  • There are about a dozen built-in iteration methods, plus lots more added by libraries like lodash.

Iterators are Callback Functions

A callback function is any function passed to another function as an argument. Callback functions are then called by the outer function in order to do some work.

function printDate(value) {
  console.log('The date is: ' + value);
}

function currentDate(callback) {
  let now = Date().toLocaleString();
  // calling the inner callback
  callback(now);
  // back in the outer function
  console.log('All Done!');
}

currentDate(printDate)

The forEach Method 1

forEach works a lot like for..of, but passes each value to a callback function as an argument, one after another.

let names = ['Alice', 'Bob', 'Carol'];

function printUpperCase(name) {
  console.log(name.toUpperCase())
}

names.forEach(printUpperCase);

/* Prints the following:
ALICE
BOB
CAROL
*/

The forEach Method 2

Given an array of names:

let names = ['Alice', 'Bob', 'Carol'];

This code:

for (let name of names) {
  console.log(name.toUpperCase())
}

And this code:

function printUpperCase(name) {
  console.log(name.toUpperCase())
}

names.forEach(printUpperCase)

Print the same thing:

ALICE
BOB
CAROL

The find Method

Find the first item that matches the condition function

let names = ['Alice', 'Bob', 'Carol'];

function beginsWithC(word) {
  return word.charAt(0).toUpperCase() === 'C';
};

names.find(beginsWithC);
//=> 'Carol'

Note that:

  • beginsWithC function must return a true or false value
  • find method returns a single item from the array, or undefined

Lab: Find a Berry

Given the following array:

let fruits = ['Apple', 'Blueberry', 'Cherry', 'Date', 'Elderberry']

Write code that uses find to return the first item that ends with the string 'berry'

(in this case, 'Blueberry')

Solution

let fruits = ['Apple', 'Blueberry', 'Cherry', 'Date', 'Elderberry'];

function endBerry(word) {
  return word.endsWith("berry")
}

fruits.find(endBerry);

The filter Method

The filter iteration method returns all matching values, in a new array

Note that * beginsWithC function must *still return a true or false value * filter method returns an Array of all values passing the test

let names = ['Alice', 'Bob', 'Charlie', 'Carol', 'David'];

function beginsWithC(word) {
  return word.charAt(0).toUpperCase() === 'C';
}

names.filter(beginsWithC)
//=> [ 'Charlie', 'Carol' ]

Lab: Find all Berries

Given the following array:

let fruits = ['Apple', 'Blueberry', 'Cherry', 'Date', 'Elderberry']

Now go find your code from the previous lab ("Find a Berry") and change it to use filter to return a new array containing all the fruits that end with the string 'berry'

Find All Berries Solution

Solution

let fruits = ['Apple', 'Blueberry', 'Cherry', 'Date', 'Elderberry'];

function endBerry(word) {
  return word.endsWith("berry")
}

fruits.filter(endBerry);

The map Method

The map iteration method returns a new array whose elements correspond to the elements of the original array.

let names = ['Alice', 'Bob', 'Charlie', 'Carol', 'David'];
function upperCase(word) {
    return word.toUpperCase();
}
names.map(upperCase)
//=> [ 'ALICE', 'BOB', 'CHARLIE', 'CAROL', 'DAVID' ]

It's called "map" because in a mathematical sense, it defines a mapping from one collection to another.

from to
'Alice' 'ALICE'
'Bob' 'BOB'
'Charlie' 'CHARLIE'
'Carol' 'CAROL'
'David' 'DAVID'

Lab: Titleize with Map

Remember the capitalize function? It capitalizes the first letter of a string and makes the whole rest of the string lowercase.

function capitalize(word) {
  let firstLetter = word[0];
  let restOfWord = word.slice(1);
  return firstLetter.toUpperCase() + restOfWord.toLowerCase();
}

Now please try to write a function that capitalizes each word in a string.

titleize("the rain in spain falls MAINLY on the PLAIN")
  //=> 'The Rain In Spain Falls Mainly On The Plain'

There is a solution on the next slide, but please try on your own first.

Think about how to combine the .map(someFunction) method with the capitalize(someWord) function.

Solution: Titleize with Map

Solution

function capitalize(word) {
  let firstLetter = word[0];
  let restOfWord = word.slice(1);
  return firstLetter.toUpperCase() + restOfWord.toLowerCase();
}

function titleize(phrase) {
  let wordArray = phrase.split(' ');
  let capitalizedWords = wordArray.map(capitalize);
  let finalSentence = capitalizedWords.join(' ');
  return finalSentence;
}

Solution: Titleize with ForEach

Solution

function capitalize(word) {
  let firstLetter = word[0];
  let restOfWord = word.slice(1);
  return firstLetter.toUpperCase() + restOfWord.toLowerCase();
}

function titleize(phrase) {
  let wordArray = phrase.split(' ');
  let capitalizedWords = [];

  // Use a variable and update it
  function capitalizeAndPush(word) {
    let completed = capitalize(word);
    capitalizedWords.push(completed);
  }

  // forEach does not return a value
  wordArray.forEach(capitalizeAndPush);
  let finalSentence = capitalizedWords.join(' ');
  return finalSentence;
}

Aside: Method Chaining

  • The solution above uses method chaining -- taking the result of one method, and immediately calling a method on that result without assigning it to a variable, again and again until you get a final result.
  • Method chaining can be very elegant, but it can also be very dense, making the code harder to understand, test, and debug.
  • "Unspooling" a method chain into intermediate variables (like example 3) can make the code easier to follow, but it can also make it cluttered and obscure the algorithm.

Reduce

The reduce method keeps track of a running total (aka accumulator or memo); whatever value the function returns is used as the accumulator for the next pass.

Here's some code that counts the total number of letters across all words in an array:

let names = ['Alice', 'Bob', 'Charlie', 'Carol', 'David'];
const reducer = function(accumulator, word) {
    return accumulator + word.length;
};
let totalCount = names.reduce(reducer, 0); //=> 25

The reduce algorithm can be difficult to follow at first; here's a walkthrough:

Iteration Accumulator In Word Length Accumulator Out
1 0 'Alice' 5 0 + 5 = 5
2 5 'Bob' 3 5 + 3 = 8
3 8 'Charlie' 7 8 + 7 = 15
4 15 'Carol' 5 15 + 5 = 20
5 20 'David' 5 20 + 5 = 25

See how the accumulator is used to pass information from one iteration to the next?

Iteration Methods in Emoji

map filter reduce in emoji

(image used with permission by @AccordionGuy based on a tweet by @steveluscher -- with a working implementation 😲 in Swift)