What an array is
An array is one value that holds a list of values, in order. Each item sits in a numbered slot. That number is its index, and counting starts at 0, not 1.
Square brackets make an array, with commas between the items. The engine puts "apple", "pear" and "fig" in slots 0, 1 and 2, and the array records its length: 3. const names it fruits.
Reading items
fruits[0] means "the item at index 0". The engine looks in slot 0 and hands "apple" to console.log, which prints apple. The first item is always at index 0.
fruits.length is how many items the array holds: 3. The last index is one less, 2. Asking for fruits[3] now gives undefined, which means "no value": there is no item there yet.
Changing and growing
An index on the left of = changes that slot. "kiwi" replaces "pear" in slot 1; the other items stay put. const only stops the name fruits pointing at another array. The items inside can still change.
push is a method: a function that belongs to the array. It adds "plum" at the end, in a new slot 3. The array grows by itself, and its length goes up from 3 to 4.
The last item is always at index length − 1. Here fruits.length is 4, so fruits[4 − 1] is fruits[3]: "plum". This works however long the array grows.
Visiting every item
for...of visits every item in order, from index 0 up. Each time round, f holds the next item and console.log prints it: apple, kiwi, fig, plum. Four items, so the loop body runs four times.
What happens
// step 1/8 · array
array one value holding a list, in order
item one value in the list
index the number of its slot: 0, 1, 2, ...
the first item is at index 0
length how many items there are
In JavaScript an array is a kind of object: typeof ["a"] is "object", and Array.isArray() tells arrays apart. fruits holds a reference to the array, which is why const fruits can still have its items changed. The slots side by side are a picture of the idea. Engines store arrays in different ways inside, but indexes, length and push always behave as shown.