0

I am currently practicing while loops and then turning loops into recursion below is an example of code that produces the result but I am unsure why I am getting a type error:

const frenchie = {
    name: "Lokys",
    friend: {
        name: "Benken",
        friend: {
            name: "Weller"
        }
    }
}

let currentFrench = frenchie
while(currentFrench !== null){
    console.log(currentFrench.name)
    currentFrench = currentFrench.friend
    
}

Above code will produce the output I want in regards to the name but the error message I see is:

Uncaught TypeError: Cannot read properties of undefined (reading 'name') at script.js:13:31

However, if I change the code to this:

const frenchie = {
    name: "Lokys",
    friend: {
        name: "Benken",
        friend: {
            name: "Weller"
        }
    }
}

let currentFrench = frenchie
while(currentFrench != null){
    console.log(currentFrench.name)
    currentFrench = currentFrench.friend
    
}

It produces the same result but with no type error. I THOUGHT !== using a strict bang operator (i think this is the right term I am still learning) like this would be the best route. Similar to house I try to use const vs let when it makes sense to not produce side effects or == vs ===

VLAZ
  • 26,331
  • 9
  • 49
  • 67
ashton8504
  • 47
  • 5
  • 2
    Strict inequality means that the `undefined` you get is ***not*** equal to `null`, thus the code proceeds with `currentFrench = undefined`. Which then throws an error. However, `undefined` and `null` are loosely equal thus for `currentFrench = undefined` the check `currentFrench != null` is `false`. – VLAZ Mar 02 '23 at 10:45
  • 1
    `while` loop is rarely a good way to iterate an object, see https://stackoverflow.com/questions/11922383/how-can-i-access-and-process-nested-objects-arrays-or-json – Teemu Mar 02 '23 at 10:48
  • @Teemu - A `while` loop seems absolutely fine here to me (as far as we can tell from the question -- that is, assuming an unknown number of layers). – T.J. Crowder Mar 02 '23 at 10:55
  • @T.J.Crowder Well, I said "_rarely_". These questions tend to evolve, and when OP finally responses, we'll probably find a question which will need recursive approach (not that it couldn't be built on `while` loops too), unless poor Weller has no friends at all. – Teemu Mar 02 '23 at 11:02
  • @Teemu - :-) Yeah, recursion is a good point. – T.J. Crowder Mar 02 '23 at 11:07

2 Answers2

2

The innermost friend object has no friend property, so accessing it gives you undefined. But you're testing for null, not undefiend. With === and !==, null and undefined are distinct. With == and !=, they're treated as though they were the same.

In this particular case, since you're expecting currentFrench to be either an object or undefined, the idiomatic way to write it would be simply while (currentFrench). But you could use != null or (if it will never be null) !== undefined if you like.


I THOUGHT !== using a strict bang operator (i think this is the right term I am still learning)

It's the "strict inequality operator."

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
1

It is because you are advancing to a .friend that doesn't exist

On the final step, you are expecting this to yield undefined:

currentFrench = currentFrench.friend

That happens, but then the while criterion is not met: currentFrency (undefined) really is not exactly equal to null, so the while continues, and you get an error when you try to advance again into the non-existent friend of the already non-existent person.

I suggest you change the while to:

 while (currentFrench)

That would get the concept across to the reader as well.

In principle you could use while (currentFrench !== undefined)

However, doing so always makes me laugh because it reminds me that you can create a variable called undefined and set it to something, but can't actually read it back.

enter image description here

ProfDFrancis
  • 8,816
  • 1
  • 17
  • 26
  • "*someone could cheekily create a variable called undefined to mess up your life.*" not easily possible nowadays. Attempting to overwrite the global `undefined` *mostly* leads to an error. You can, however, shadow it: `fn = (undefined) => console.log(typeof undefined); fn("hello");` – VLAZ Mar 02 '23 at 10:50
  • 1
    THANK YOU, this makes total sense. I just went through control flow lessons and trying to be very detailed in what I am writing to connect the parts on JS but this makes so much sense. – ashton8504 Mar 02 '23 at 10:52
  • @VLAZ I didn't realise it had changed! I've added what actually happens on Chrome currently. Replaces one hilarious situation with another. – ProfDFrancis Mar 02 '23 at 10:53