Discussion:
Programming Corner - JavaScript Fundamentals - Arrays and looping
(too old to reply)
Steve Carroll
2025-01-20 22:20:39 UTC
Permalink
Reference: <vmekhl$74sp$***@fretwizzer.eternal-september.org>
Setup info: <vmgi9e$u5m6$***@fretwizzer.eternal-september.org>
Variables: <vmh41h$u5m6$***@fretwizzer.eternal-september.org>
Functions: <vmh7ln$u5m6$***@fretwizzer.eternal-september.org>

Arrays are one of JavaScript's data structures that are used to store
multiple values in a single variable. They enable you to organize and
manage lots of data, especially when the items (the 'elements') of the
array are related:

let colors = ['red', 'green', 'blue'];

The elements of an array are separated by commas. One important thing to
know about arrays is that the elements within them are numbered and the
numbering starts at zero (0). In the 'colors' array 'red' is element 0,
'green' is element 1 and 'blue' is element 2.

These numbers can be used to 'access' whatever element you want in a
given array. For example, to get (to 'access') the string 'blue' in the
'colors' array up above, you would do this:

colors[2]; // outputs: 'blue'

Those square brackets are referred to as 'bracket notation'.

Above, all the elements are of the 'string' data type but they can be
any data type, you can even mix types:

let myStuff = [10, 'Hello', true, null, 'world!', 3.14, false];

myStuff[1]; // outputs: 'Hello'

If you've read the material on "Functions", you'll probably understand this:

function greet(name) {
console.log(myStuff[1], myStuff[4] + ' And you too, ' + name )
}

Arrays can even contain other arrays:

let myArray = ['apple', 'banana', ['orange', 'pear'], 'grape', 'cherry']

You can see that 'element 2' is a 'nested' array. How do you access it?

myArray[2][1]; // outputs: 'pear'

The '2' represents element 2 (the 3rd item) in the outer array, the '1'
is element 1 in the nested (inner) array (arrays like this are called:
multi-dimensional).

Suppose you have a one dimensional (flat, nothing nested) array of
fruits you wanted to log to the console?

let fruits = ['kiwi', 'banana', 'cherry', 'apple', 'fig', 'lemon', 'honeydew', 'grape', 'elderberry', 'date']

How many fruits are in there? You can count them, or you can have JS do
it... and you many want to!

You can do it using a 'property' called 'length', which can use 'bracket
notation', just like you used with elements in the array:

fruits['length']

Note that 'length' is in between quotes. This property is given to an
array when you create it. The 'length property' gets updated with each
element you add/subtract to the array. Properties like this can also be
accessed using something called 'dot notation':

fruits.length // no quotes needed

Aside from properties, arrays also have 'methods' (functions) that are
built-in for your use (more on that below).

Back to logging the fruit. Suppose there was 100 fruits, or 1000?
Instead of writing out all those console.log() statements like this...

console.log(fruits[0]);
console.log(fruits[1])

...

console.log(fruits[999]);

... here's a way to have JS do the work... using the 'length property'
and 'bracket notation' inside of an 'old school for loop':

for (let i = 0; i < fruits.length; i++) {
console.log(fruits[i])
}

What's going on? The variable 'i' is a number, right? And, at first,
it has a value of '0' (let i = 0).

So 'fruits[i]', which starts at fruits[0] because we started with 'i'
set to 0, will 'access' element 0 ('kiwi') in the fruits array. OK, we
get fruits[0] but what about the rest of the elements? This section...

(let i = 0; i < fruits.length; i++)

... is the loop's structure and it has three parts, separated by
semicolons.

1. Initialize a counter - 'let i = 0'

If you're going to loop, it helps to have a counter and this part sets
the initial value of the loop's 'counter' (variable 'i'). Notably, it
doesn't have to be set to 0 but that's common, it doesn't even have to
be 'i' but that's also common.

2. Check the 'condition' - 'i < fruits.length'

The condition gives a read on the current status of the loop by checking
the value of 'i' against 'fruits.length' through *each* iteration of the
loop, it's what checks to see if the loop should continue, or not. As
long as the condition is true... in this case, as long as the value of
the 'i' variable is 'less than' the value of 'fruits.length' (10)... the
loop will continue to run.

Wait a minute, won't 'i' *always* be less than 10?! "Hmmm..."

3. Increment the counter - 'i++'

This runs in each iteration of the loop, updating the loop's counter
variable ('i') by 1 each time.

'i++' is shorthand for 'i = i + 1'

(so, no, 'i' won't *always* be less than 10)

Eventually, the value of 'i' will exceed the 'length' of the 'fruits'
array and the loop will stop.

There is another way to loop over an array, the 'for... of' loop.

<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of>

for (let fruit of fruits) {
console.log(fruit);
}

Here, the word 'fruit' essentially replaces the variable 'i' in the 'old
school for loop' (fruits[i]). Like 'i' did earlier, 'fruit' now directly
represents each element of the array as you loop through it, one after
the other.

So why did I cover the 'old school' loop? It can come in handy for some
things. For example, it's easy to put a number in front of each element:

for (let i = 0; i < fruits.length; i++) {
console.log(i+1, fruits[i])
}

This can be done with a 'for... of' loop but it's not quite as
straightforward. You can also do this 'old school':

for (let i = 4; i < fruits.length; i++) {
console.log(i+1, fruits[i])
}

Or this:

for (let i = fruits.length - 1; i >= 5; i--) {
console.log(fruits[i]);
}

If your loop requires more granularity, you might find 'old school' is
the way to go... and it can be faster, depending on what you're doing.

I'll close by showing you a bit about methods (built-in functions)
available to an array. Like the 'length' property, it also uses 'dot
notation' (and requires parens). Let's apply the 'sort' method to our
'colors' array from earlier:

colors.sort() // outputs: ['blue', 'green', 'red']

That didn't just reverse the colors (as it appears), it sorted them
alphabetically. Try it on the fruits array.

Note: If you've entered an array into dev tools, you can see all the
available properties and methods by typing the name of the array
followed by a dot ('.'), you'll get a scrollable menu with all kinds of
useful things. Try this method, using 'myArray' from above (make sure
it's in memory in dev tools):

myArray.flat() // no longer multi-dimensional

Or this:

myArray.flat().reverse() // you can often 'chain' them!

Or this:

myArray.flat().concat(colors) // 'concat' combines arrays

To be able to manipulate the elements of an array (add to, subtract from
and much more) check out some of the methods available:

<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array>
Apd
2025-01-21 00:35:55 UTC
Permalink
Post by Steve Carroll
for (let fruit of fruits) {
console.log(fruit);
}
I've been discovering the difference (the hard way!) between for...of
and for...in. A long SO discussion gave some ways to remember:

<quote>
for of is not for *o*bjects (so it's for iterables)

for in is not for *i*terables (so it's for objects)

Another trick:

for in returns object *in*dices (keys) while for of returns values
</>

I see that for...of (introduced in ES6) is said to be preferable when
applicable, which it is for arrays.
Steve Carroll
2025-01-21 01:10:55 UTC
Permalink
Post by Apd
Post by Steve Carroll
for (let fruit of fruits) {
console.log(fruit);
}
I've been discovering the difference (the hard way!) between for...of
<quote>
for of is not for *o*bjects (so it's for iterables)
for in is not for *i*terables (so it's for objects)
for in returns object *in*dices (keys) while for of returns values
</>
I like 'em!
Post by Apd
I see that for...of (introduced in ES6) is said to be preferable when
applicable, which it is for arrays.
It's easier to read.

ES6 also gave us symbols...

const obj = {
a: 1,
b: 2,
c: 3,

[Symbol.iterator]() {
const entries = Object.entries(this)
let index = 0
return {
next: () => index < entries.length ? { value: entries[index++], done: false } : { done: true }
};
}
}


Guess what you can do with that ;)

(it's not a generator, despite that next() method in there)
Apd
2025-01-21 12:06:25 UTC
Permalink
Post by Steve Carroll
Post by Apd
for in returns object *in*dices (keys) while for of returns values
</>
I like 'em!
Post by Apd
I see that for...of (introduced in ES6) is said to be preferable when
applicable, which it is for arrays.
It's easier to read.
Is it? You can't (I can't) infer the meaning of "of" and "in" when
used to iterate. Also, saying an object is not "iterable" when a loop
can be run over it is confusing.
Post by Steve Carroll
ES6 also gave us symbols...
const obj = {
a: 1,
b: 2,
c: 3,
[Symbol.iterator]() {
const entries = Object.entries(this)
let index = 0
return {
false } : { done: true }
};
}
}
Guess what you can do with that ;)
I guessed right - it makes the object iterable. I'm not sure why you'd
do that instead of chosing a Map to begin with. The syntax is weird
and I'm not sure what a "symbol" really is.
Post by Steve Carroll
(it's not a generator, despite that next() method in there)
Something else I was unfamiliar with.
Steve Carroll
2025-01-21 14:14:43 UTC
Permalink
Post by Apd
Post by Steve Carroll
Post by Apd
for in returns object *in*dices (keys) while for of returns values
</>
I like 'em!
Post by Apd
I see that for...of (introduced in ES6) is said to be preferable when
applicable, which it is for arrays.
It's easier to read.
Is it?
To someone whose basic understanding of the word 'for' may revolve soley
around the concept of looping (i.e. too many junior devs!) it might be.
I'd say it's also less cluttered for anyone to look at (despite its
apparent lack of meaning).
Post by Apd
You can't (I can't) infer the meaning of "of" and "in" when
used to iterate. Also, saying an object is not "iterable" when a loop
can be run over it is confusing.
In this context, 'iterable' merely means it (the method in question) has
a default iterator. IOW, the context is the method itself... for
example, it doesn't address the fact that you can iterate over an
object 'old school' as that has nothing to do with the method you got
an error from.
Post by Apd
Post by Steve Carroll
ES6 also gave us symbols...
const obj = {
a: 1,
b: 2,
c: 3,
[Symbol.iterator]() {
const entries = Object.entries(this)
let index = 0
return {
false } : { done: true }
};
}
}
Guess what you can do with that ;)
I guessed right - it makes the object iterable. I'm not sure why you'd
do that instead of chosing a Map to begin with.
Even though Map can hold objects of some depth (not flat), the need for
traversal still exists. Not that you'd necessarily use 'for...of' on
objects, the point is, you can... if you need to customize your
iteration it's an option. Given the way each works, you may choose one
over the other. I don't use it so I'm far from an expert on why you
would, I'm just aware there are differences in the workings.
Post by Apd
The syntax is weird
It's JS, king of the weird syntax! ;)
Post by Apd
and I'm not sure what a "symbol" really is.
From what little I've seen on the net, this line from MDN seems to be a
major use of it:

"Symbols are often used to add unique property keys to an object that
won't collide with keys any other code might add to the object, and
which are hidden from any mechanisms other code will typically use to
access the object."

<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol>

I get all the 'unique' I've needed thus far from Map but I'm just a
hobbyist so I don't know all of what the pros use it for outside of
collision protection. Maybe library authors use it because the way JS
files are 'combined' is a bit hairy? MDN also mentions encapsulation so
I guess even weak protection like that could be part of it.
Post by Apd
Post by Steve Carroll
(it's not a generator, despite that next() method in there)
Something else I was unfamiliar with.
I think it's another one of those 'things' that's useful in an
asynchronous world while using a synchronous language. JS needs to go on
a diet ;)
Apd
2025-01-21 15:55:30 UTC
Permalink
Post by Steve Carroll
Post by Apd
Post by Steve Carroll
Post by Apd
I see that for...of (introduced in ES6) is said to be preferable when
applicable, which it is for arrays.
It's easier to read.
Is it?
To someone whose basic understanding of the word 'for' may revolve soley
around the concept of looping (i.e. too many junior devs!) it might be.
I'd say it's also less cluttered for anyone to look at (despite its
apparent lack of meaning).
Less cluttered than the old C-like for loop but for...of is no better
to read than for...in from that perspective, which is what I thought
you were saying. I meant for...of is preferred to for...in when it's
available.
Post by Steve Carroll
Post by Apd
You can't (I can't) infer the meaning of "of" and "in" when
used to iterate. Also, saying an object is not "iterable" when a loop
can be run over it is confusing.
In this context, 'iterable' merely means it (the method in question) has
a default iterator.
Indeed, but it can still be confusing.

[...]

Regarding the rest, I think we're roughly at the same level, i.e. we
know of it but haven't used it.
Post by Steve Carroll
Post by Apd
Post by Steve Carroll
(it's not a generator, despite that next() method in there)
Something else I was unfamiliar with.
I think it's another one of those 'things' that's useful in an
asynchronous world while using a synchronous language. JS needs to go on
a diet ;)
With so much available, it would be handy to know what to choose from,
between and why; to have some use cases for these apparently esoteric
features and also non-use cases where features are considered bad
practice, obsolete or superceded. MDN sometimes mentions these things.
Steve Carroll
2025-01-21 18:14:27 UTC
Permalink
Post by Apd
Post by Steve Carroll
Post by Apd
Post by Steve Carroll
Post by Apd
I see that for...of (introduced in ES6) is said to be preferable when
applicable, which it is for arrays.
It's easier to read.
Is it?
To someone whose basic understanding of the word 'for' may revolve soley
around the concept of looping (i.e. too many junior devs!) it might be.
I'd say it's also less cluttered for anyone to look at (despite its
apparent lack of meaning).
Less cluttered than the old C-like for loop but for...of is no better
to read than for...in from that perspective, which is what I thought
you were saying. I meant for...of is preferred to for...in when it's
available.
Ah, sorry for 'stooping up' there. I've often (mistakenly) linked 'of'
with 'the keys *of* an object' and 'in with the 'elements in an array'
for some reason <shrug>.
Post by Apd
Post by Steve Carroll
Post by Apd
You can't (I can't) infer the meaning of "of" and "in" when
used to iterate. Also, saying an object is not "iterable" when a loop
can be run over it is confusing.
In this context, 'iterable' merely means it (the method in question) has
a default iterator.
Indeed, but it can still be confusing.
No doubt!
Post by Apd
[...]
Regarding the rest, I think we're roughly at the same level, i.e. we
know of it but haven't used it.
Post by Steve Carroll
Post by Apd
Post by Steve Carroll
(it's not a generator, despite that next() method in there)
Something else I was unfamiliar with.
I think it's another one of those 'things' that's useful in an
asynchronous world while using a synchronous language. JS needs to go on
a diet ;)
With so much available, it would be handy to know what to choose from,
between and why; to have some use cases for these apparently esoteric
features and also non-use cases where features are considered bad
practice, obsolete or superceded. MDN sometimes mentions these things.
Yes, and it can even provide good reasons (it's much more 'in depth' on
many things than it used to be).
Apd
2025-01-21 20:54:47 UTC
Permalink
Post by Steve Carroll
Post by Apd
Less cluttered than the old C-like for loop but for...of is no better
to read than for...in from that perspective, which is what I thought
you were saying. I meant for...of is preferred to for...in when it's
available.
Ah, sorry for 'stooping up' there. I've often (mistakenly) linked 'of'
with 'the keys *of* an object' and 'in with the 'elements in an array'
for some reason <shrug>.
That would seem a logical interpretation if it were true.

Loading...