Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

Either array iteration or string conversion problem

So all I am trying to do is get an average of 9 values and display them to the user. For now, I am using pop up windows (alert and prompt). When I hit run, my program runs and I input 9 values. However, at the end of the program, the alert window displays, "NaN". I thought wrapping the prompt() in a parseFloat() would fix it but it hasn't (I want the number displayed to be a float btw). Can anyone help out?

var i;
var itemList = [];
itemList = ["prim", "spec", "heavy", "ghost", "helm", "chest", "legs", "class item", "artifact"];

for (i = 0; i < itemList.length; i++) {
   var lightLevel;
   var itemLight = parseFloat(prompt("Enter Light level for " + itemList[i] + ": "));
   lightLevel += itemLight; 
}
var averageLight = lightLevel / 9;
alert("Light level is currently: " + averageLight);

Solved my own question

3 Answers

Steven Parker
Steven Parker
243,658 Points

I notice a couple of issues:

  • you're incrementing an unitialized variable (lightLevel)
  • you're referencing that same variable outside the scope where it was created

:point_right: Try moving the definition of lightLevel outside the loop and give it a starting value:

var i;
var itemList = [];
itemList = ["prim", "spec", "heavy", "ghost", "helm", "chest", "legs", "class item", "artifact"];

var lightLevel = 0;
for (i = 0; i < itemList.length; i++) {
   var itemLight = parseFloat(prompt("Enter Light level for " + itemList[i] + ": "));
   lightLevel += itemLight; 
}
var averageLight = lightLevel / 9;
alert("Light level is currently: " + averageLight);

@Steven Parker can you explain why moving lightLevel outside the loop worked? I am not sure what I did but nothing would work for me until I set the initial value of lightLevel and lightItem to 0.0.

It seem that if you don't set lightLevel equal to 0 to start it will return NaN. I have been looking though MDN and cannot figure out why.

Steven,

javascript does not have block level scope. It only has global and function level scope.

So even if the variable is declared inside the loop, the declaration is hoisted to the top of either the global code or the top of the function if this code is within a function. It's a best practice to declare variables at the top but doing it inside the loop wouldn't cause any issues.

The following code runs perfectly fine but not a good practice since you're relying on the hoisting instead of being explicit about it.

lightLevel = 0;

for (var i = 0; i < 10; i++) {
  var lightLevel;

  lightLevel += 5;
}

console.log(lightLevel); // 50

I think the only issue was the uninitialized variable.

Shawn,

lightLevel is undefined the first time lightLevel += itemLight; is reached. It's been declared but hasn't been given a value yet.

You're trying to do something like lightLevel = undefined + 5.0; the first time through the loop. This results in NaN being assigned to lightLevel

Next time through the loop you have something like lightLevel = NaN + 3.0 Any calculations with NaN continue to result in NaN. lightLevel is therefore stuck at NaN for the rest of the loop.

Awesome! Thanks Jason!

Steven Parker
Steven Parker
243,658 Points

As I understand it, "hoisting" is only applied to function declarations, not to variable declarations.

Hey Steven,

Are you getting to some old notifications here? :)

I'm pretty sure that you do have variable hoisting with the var keyword at least. This doesn't apply anymore with let and const

I don't know if you had a chance to try the code in my comment but I don't think it would be able to log 50 if there was block level scope. In my example, if you replace the var keyword with let then you'd have 2 lightLevel variables. A global one and one local to the loop.

In that case, it logs 0.

The same thing happens with the index variable even though I used the var keyword in the for statement. You could log the value of i after the loop and it would be 10. What's happening behind the scenes is more like how you and Bryan wrote it, with var i; at the very top.

It's certainly better to write the code the way you did in your answer and not how I have in my previous comment but they would both work the same way.

Steven Parker
Steven Parker
243,658 Points

After looking it up I see that "JavaScript only hoists declarations, not initializations." I wasn't previously aware of that, partly because I very rarely declare without initializing, and as matter of practice never assign before declaring.

I love how contributing to the forum leads to learning things I might never know otherwise. :smile:

Yes, I've certainly learned a lot from your answers as well as others.

I'd say this variable hoisting is probably one of the quirks of javascript that can lead to a lot of confusion with beginners.

I think it's a good thing that we'll be moving on to using let and const and at least in this respect it will work more like what we're used to with C-like languages.

Hey Brian I know you said you solved your own question but you did not say how. Here is what I came up with. I found 2 main issues. One was variable scope and the other was initializing lightLevel and itemLight with a value of 0.0.

var itemList = ["prim", "spec", "heavy", "ghost", "helm", "chest", "legs", "class item", "artifact"];
var lightLevel = 0.0;
var itemLight= 0.0;

for (i = 0; i < itemList.length; i++) {
  itemLight = prompt("Enter Light level for " + itemList[i] + ": ");
  lightLevel += parseFloat(itemLight);
}

var averageLight = lightLevel / 9.0;
alert("Light level is currently: " + averageLight);

I'm not sure if loops can have "local" variables like functions but if they can then your problem might be that "lightLevel" is a local variable hidden inside the loop - but I'm not sure if I'm correct because I'm still very new to JS....

anyway, I hope this could help you in any way :)