I had this task: "Use the rest parameter to create an average() function that calculates the average of an unlimited amount of numbers". And wen I ran this code, I have 0 answer.
function average(...nums) {
let total = 0;
for (const num of nums) {
total += num;
len = nums.length;
}
total = total/len;
return total;
}
console.log(average());
But why? Why when I divide by the undeclared variable 0 the answer is 0 and not NaN? It's NaN if I run the following code (with declared variable).
function average(...nums) {
let total = 0,
len;
for (const num of nums) {
total += num;
len = nums.length;
}
total = total / len;
return total;
}
console.log(average());
P.s. the right answer in the task is 0.
The reason this happens is that in loose mode (i.e. not strict mode), assigning to undeclared variables makes them global.
So you run average() once with some arguments, which sets the global len to whatever number, and returns the correct average. (This is also why the udacity tests pass, the order of the tests matter. If they had run the empty input test first, it would have failed)
You then run it again with no arguments, since setting len happens inside the loop, it doesn't happen again because a for..of loop over an empty array doesn't even enter, so then the result of 0 (the sum) divided by whatever (the previous len, set to any number) will be 0.
If you had run it in strict mode, you would have gotten an error about assigning to undeclared variables, even when you run it with arguments.
This is why you always:
Use strict mode (add 'use strict' to your top level function or file, if you use webpack or a similar bundler, you have this by default)
Declare your variables.
A correct version of this, assuming they want an empty input to return 0, is as follows:
function average(...nums) {
'use strict'; // enter strict mode
if (nums.length === 0) { return 0; }
let total = 0;
for (const num of nums) {
total += num;
}
return total / nums.length;
}
console.log(average());
You must directly define the behavior for empty input, because strictly speaking, the average of a set of 0 numbers is undefined.
Related
Chapter 3 Functions has the following code snippet:
const power = function(base, exponent) {
let result = 1;
for(let count = 0; count < exponent; count++) {
result *= base;
}
return result;
};
console.log(power(2, 10));
// 1024
can someone explain what is going on in the code line by line, i'm confused by let result = 1 the most. Thanks!
In the first line, you're declaring a variable result. However, it's being declared with let, not var. Let is similar to var, except it can't be accessed outside the block it is defined in (including functions, loops and conditional statements). And since it's in a function here, that first line is equivalent to:
var result = 1;
In the second line:
for (let count = 0; count < exponent; count++) {}
You're looping over exponent - so the code within the {} of the loop will be executed exponent times.
In the third line:
result *= base;
You're multiplying result and base, and assigning the value to result. This line is equivalent to:
result = result * base;
Final line:
return result;
This line stops the function and returns result. The return means that whenever a function is called, it essentially is replaced with the return value (like in this line):
console.log(power(2, 10));
This calls power() with arguments 2 and 10, and logs the returned value to the console.
This example is a simple approach of building and executing an exponential function in JavaScript.
That said, we know that the below will essentially be creating something like the following in pseudocode:
print the result of (number to the power of some other number)
The code walkthrough:
// initialize a constant variable named 'power' as a function declaration with two arguments, 'base' and 'exponent' which will be used inside the function
const power = function(base, exponent) {
// declare and initialize variable called 'result' and set it with value of 1
// why this is 1, is because any number to the power of 1 is itself, so rather than setting this to 0, this must be 1 to ensure that the exponential function works accurately
let result = 1;
// let count = 0; this will initialize a variable named count to be used within the loop
// count < exponent; this is the conditional statement, it means that the loop will continue looping until the condition is met, meaning loop until 'count' is no longer less than 'exponent'
// count++; this increments the value of the initial variable, in this case 'count' for every trip through the loop for the duration that the condition statement remains true
for (let count = 0; count < exponent; count++) {
// multiply the 'result' variable by the 'base' variable and set it as the new value of the 'result' variable
result *= base;
}
// return the 'result' variable so that it is now available outside of the function
return result;
};
// pass in the 'base' and 'exponent' arguments for the function 'power' in order to get the value (effectively, 2^10), and then print this value to the console
console.log(power(2, 10));
// 1024
I'm currently learning javascript by following the book "you dont know js".
In the section "type & grammer", when discussing implicit vs explicit boolean convertion, the author mentioned
//come up with a function that make sure only one argument is truthy
//implicit convertion
function onlyOne() {
var sum = 0;
for (var i=0; i < arguments.length; i++) {
// skip falsy values. same as treating
// them as 0's, but avoids NaN's.
if (arguments[i]) {
sum += arguments[i];
}
}
return sum == 1;
}
//explicit convertion
function onlyOne() {
var sum = 0;
for (var i=0; i < arguments.length; i++) {
sum += Number( !!arguments[i] );
}
return sum === 1;
}
Is the explicit coercion form of this utility "better"? It does avoid
the NaN trap as explained in the code comments. But, ultimately, it
depends on your needs. I personally think the former version, relying
on implicit coercion is more elegant (if you won't be passing
undefined or NaN), and the explicit version is needlessly more
verbose.
My question is, what NaN trap is the author talking about? I thought when undefined and NaN is converted to boolean value, regardless of whether it is converted implicitly or explicitly, they both results in false. And passing undefined and NaN to the implicit function is ok, right?
I think that an example of a real explicit check would be...
function onlyOne() {
var sum = 0;
for (var i=0; i < arguments.length; i++) {
sum += Boolean( arguments[i] );
}
return sum == 1;
}
This will of course avoid / guard against NaN and should return false if no arguments are present; if no arguments are truthy and of course -if more than one arguments are truthy.
the 2nd example always avoid NaN,because Number(!!string) and Number(!!object) are both converted to 1
enter image description here
I am in the midst of completing some JavaScript algorithmic challenges and I had to factorialize a number as part of one of them. After searching through stack and other places I entered a correct code block:
function factorialize(num) {
if(num === 0) {
return 1;
}
if(num < 0 ) {
return undefined;
}
for(var i = num; --i; ) {
num *= i;
}
return num;
}
factorialize(5);
It it returns a correct result. What I am struggling to understand however is why the for loop doesn't have a second statement, and why it can run for ever? I have an inkling it's because as soon as i value is 0, any subsequent negative number that is generated will be multiplied by 0 and so only the integer numbers will form the result. But why does the function return a valid number, if the loop is still running to -infinity and hasn't been told to stop when reaching a certain value?
the second part of your for loop is the Condition:
An expression to be evaluated before each loop iteration. If this expression evaluates to true, statement is executed. This conditional test is optional. If omitted, the condition always evaluates to true. If the expression evaluates to false, execution skips to the first expression following the for construct.
Once --i reaches 0, it evaluates to false (falsey) and the for "exits"
adding a console.log(i) to your for loop will help demonstrate that
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for
All elements in a for-loop's expression are optional.
The second part of the for-loop is used to express the for-loop's condition. The condition is evaluated on every iteration, and when it evaluates to false, the loop is exited.
In this case, that second part that expresses the condition is --i. This means that on every iteration, i will be decremented by 1, until it finally reaches zero (0). Since 0 is considered to be a falsey value in Javascript, the loop exits.
for (a; b; c)
is a direct equivalent to
a;
while (b) {
c;
}
You're mistaken here because you seem to think that c is what determines the end of the loop, but b actually is. You can omit the third loop statement if you don't need it (as well as the first one).
Here, your loop is equivalent to:
var i = num;
while (--i) {
num *= i;
}
while (--i) does two things:
Decrement i (before anything else)
Check that i != 0 (this is the actual loop condition).
If it was i--, note that the operations would be done in the opposite order.
If you find the code hard to read, you can also write it this way for the same results:
for (var i = num - 1; i != 0; i--) {
num *= i;
}
Normally you would have :
for(var i = 0; i < num; i++)
the second statement is a boolean continuation expression.
So when you have
for(var i = num; i--;)
The second is still a boolean continuation expression and when i get to 0 it evaluated to false.
I have written the following program in javascript:
function recursiveSum(a) {
sum = 0;
for (i=0;i<a.length; ++i) {
if (typeof a[i] === "number") {
sum += a[i];
} else if (a[i] instanceof Array) {
sum += recursiveSum(a[i]);
}
}
return sum;
}
function arraySum(a) {
// i will be an array, containing integers, strings and/or arrays like itself.
// Sum all the integers you find, anywhere in the nest of arrays.
return recursiveSum(a);
}
And I can't figure out why the result of arraySum([[1,2,3],4,5]) is 6. Why the elements after the first array are not processed?
You have a problem with Global Variables. You need to use var, it is not optional.
Both sum and i need to be declared with var.
var sum = 0;
for (var i=0;i<a.length; ++i) {
Your sum and i variables are globals, because you haven't declared them as local to the function. You're falling prey to The Horror of Implicit Globals. It's primarily the i variable that's causing the trouble with your specific input: Since your first entry in a is an array, i gets incremented by the recursive call, and the last two entries in the array are never processed by the outer call. (But if you'd used [1, 2, [3, 4, 5]], the fact the calls share both i and sum would be causing trouble.)
Put var in front of each of them. Also look into using the new strict mode, which would have made that a useful error.
var avg = function()
{
var sum = 0;
for (var i = 0, j = arguments.length; i < j; i++)
{
sum += arguments[i];
}
return sum / arguments.length;
}
When I try to call this like:
var average = avg(2,3,5);
average; // It works fine;
But how do I call it without assigning to a variable?
If anybody can give any suggestion it will be delightful..Thanks.
You'd simply call it like this:
avg(2, 3, 5);
If you want to see the result, put it in an alert call:
alert( avg(2, 3, 5) );
You don't need to put the result from calling the function in a variable, you can do whatever you like with it.
For example, use it as the value in an alert:
alert(avg(2,3,5));
You can use it in another expression:
var message = "The average is " + avg(2,3,5);
You can use it directly in another call:
someFunction(avg(2,3,5));
You can even throw the result away by not doing anything with it, even if that's not useful in this specific situation:
avg(2,3,5);
If you don't put the result into a variable or in a compatible context, this function cannot output anything, which makes it difficult to use unless you make it output the result. Try this :
var avg = function()
{
var sum = 0;
for (var i = 0, j = arguments.length; i < j; i++)
{
sum += arguments[i];
}
var retvalue = sum / arguments.length;
consoloe.log("avg: "+retvalue);
return retvalue ;
}
Then it may help you to see whenever the function is called or not.
You need to understand the concept of expressions.
Every expression as a whole represents one value. An expression can be made up of multiple subexpressions that are combined in some manner (for example with operators) to yield a new value.
For instance:
3 is an expression (a literal, to be specific) that denotes the numeric value three.
3 + 4 is an expression, made up of two literal expressions, that as a whole yields the value 7
When you assign a value to a variable – as in var average = – the right hand side of the =-operator needs to be an expression, i.e. something that yields a value.
As you have observed, average will have been assigned the value five. It thus follows, that avg(2, 3, 5) must itself be an expression that evaluated to the value 5.
average itself is an expression, denoting the current value of said variable.
The most important thing to take away from this is, that avg() is in no way connected to var average =. avg() stands on its own, you can just think it like an ordinary value such as 5 (there are other differences of course).
If you have understood the concept of expressions and values, it should be clear that if you can do
var average = avg(2,3,5);
average; // It works fine;
You can also do
avg(2,3,5);