Javascript declaring and initializing variables - javascript

I understand that when a variable is declared it is given the value "undefined", but I don't understand why the following code doesn't work (returns NaN):
function sum() {
// return the sum of all arguments given.
var answer;
for (var i = 0; i<arguments.length; i++){
answer += (arguments[i]);
}
console.log(answer);
}
sum(4,5,3,2);
In order to get the correct answer (14), I had to initialize the answer variable:
var answer = 0;

Simply put: you cannot add to "undefined". The answer is... undefined, or not a number. You can, however, add to zero, so of course you have to initialize the variable to 0.

In essence, you're asking why undefined + 5 + 4 + 3 + 2 is NaN (not a number). The answer is that, when you treat undefined as a number, it is implicitly converted to NaN. Any operation on NaN will, in turn, result in NaN.

answer += (arguments[i]);
equals
answer = answer + (arguments[i])
answer being initially undefined, you actually have
answer = undefined + (arguments[i])
which is a NaN:
alert(undefined + 42);

Because you are trying to add a number to an undefined variable this is not possible because you are trying to add a number to answer which isn't a number until you initialize it.

Leaving answer uninitialized is equivalent to
var answer = undefined;
And since (undefined + any number) is also NaN (not a number) each loop does nothing but keep reassigning answer to NaN
console.log(undefined + 0); => NaN
console.log(NaN + 1); => NaN
console.log(NaN + 2); => NaN

Try undefined + 1 (a variable not initialized resolves to undefined) in the console: its result is NaN (Not a Number), so any next iteration NaN + some number will be NaN.
Alternatively you can use Array.reduce (see MDN for more on that) to calculate the sum:
function sum() {
// return the sum of all arguments given.
return ([].slice.call(arguments)).reduce(function (a, b) {
return a + b;
});
}
document.querySelector('#result')
.innerHTML = '<code>sum(1,4,3,5,6)</code> => ' + sum(1, 4, 3, 5, 6);
<div id="result"></div>

Related

Why is the output of `function test(){} + 1;` is 1?

Why is the output of the following code is 1
function test(){} + 1; // output: 1
Because of automatic semicolon insertion, that code is actually processed as:
function test(){}; + 1;
That's the unary plus operator, not the addition operator.
function test() or {} here is not an Object, its en empty statement and JS Cannot convert object to primitive value and find the safe route and convert this statement value to false.
{} + 1 = 1 because (false + 1) = always 1.

Why does this JavaScript function work?

Much apologies for the vague title, but I need to elaborate. Here is the code in question, which I read on http://ariya.ofilabs.com/2013/07/prime-numbers-factorial-and-fibonacci-series-with-javascript-array.html:
function isPrime(i) {
return (i > 1) && Array.apply(0, Array(1 + ~~Math.sqrt(i))).
every(function (x, y) {
console.log(x + ' ' + i % y);
return (y < 2) || (i % y !== 0)
});
}
isPrime(23);
isPrime(19);
isPrime(188);
Just for fun, I added those logs so we can see some output:
undefined NaN
undefined 0
undefined 1
undefined 2
undefined 3
undefined NaN
undefined 0
undefined 1
undefined 1
undefined 3
undefined NaN
undefined 0
undefined 0
This is the first time I have every seen apply and every, so bear with me, but my understanding is that apply basically calls the Array function, where the first argument is the substitution for its this and the second is the output...Never would think that would be useful, but this function seems to work, so...
Here, they seem to be creating an array of length equal to the square root of the number in question. I suppose that makes sense because the square root would be the largest possible factor of the number in question.
OK, so from here, if we were to log that array for, say, the first number, it would look like this:
> var i = 23;
undefined
> Array.apply(0, Array(1 + ~~Math.sqrt(i)));
[ undefined, undefined, undefined, undefined, undefined ]
Great, so it is an array of five undefined. Ok, fine, so from here, the every method is supposed to check whether every element in that array passes the callback function test (or whatever).
The Microsoft documentation specifies three possible arguments for the every method:
value
index
array
Therefore, in this example x is the value, i.e. undefined, and y is the index.
Our output agrees with that conclusion. However, I'm still fuzzy about nested return statements (if the lowest one returns, does its parent also return?), the || operator here (if the first test passes, does the every loop stop?), and just generally how this works.
EDIT
the log should be with an x, not a y. my mistake:
console.log(y + ' ' + i % y); -> console.log(x + ' ' + i % y);
EXPLANATION
So, how did I come across this code, you ask? Well, of course, the simplest way to check for a prime in Java would be like this:
public static boolean isPrime(double num) {
for (double i = 2.0; i < sqrt(num); i++) {
if (num % i == 0.0) {
return true;
}
}
return false;
}
or Python
def isPrime(num):
x = 2
isPrime = True
while x < math.sqrt(num):
if num % x == 0:
isPrime = False
break
x = x + 1
return isPrime
or js
function isPrime(n) {
for (var i = 2.0; i < Math.sqrt(n); i++) {
if (n % i === 0.0) {
return false;
}
}
return true;
}
But say I wanted to check for the largest prime factor of a number like 600851475143 These looping methods would take too long, right? I think this "hack", as we are describing it, may be even less efficient, because it is using arrays instead of integers or floats, but even still, I was just looking for a more efficient way to solve that problem.
The code in that post is basically crap. Teaching people to write code while simultaneously using hacks is garbage. Yes, hacks have their place (optimization), but educators should demonstrate solutions that don't depend on them.
Hack 1
// the 0 isn't even relevant here. it should be null
Array.apply(0, Array(1 + ...))
Hack 2
// This is just Math.floor(x), but trying to be clever
~~x
Hack 3
// this is an outright sin; totally unreadable code
// I bet most people don't know the binding precedence of % over +
y + ' ' + i % y
// this is evaluated as
y + ' ' + (i % y)
// example
2 + ' ' + (5 % 2) //=> "2 1"
I'm still fuzzy about nested return statements (if the lowest one returns, does its parent also return?),
No. A return only return the function the statement exists in
the || operator here (if the first test passes, does the every loop stop?)
No. Array.prototype.every will return false as soon as the callback returns a false. If a false is never returned from the callback, .every will return `true.
function isEven(x) { return x % 2 === 0; }
[2,4,5,6].every(isEven); //=> false, stops at the 5
[2,4,6].every(isEven); //=> true
Here's an example of .every short circuiting
[1,2,3,4,5,6].every(x=> {console.log(x, x<4); return x<4;});
// 1 true
// 2 true
// 3 true
// 4 false
//=> false
See how it stops once the callback returns false? Elements 5 and 6 aren't even evaluated.
... and just generally how this works.
&& kind of works like Array.prototype.every and || kind of works like Array.prototype.some.
&& will return false as soon as the first false is encountered; in other words, it expects every arguments to be true.
|| will return true as soon as the first true is encountered; in other words, it expects only some argument to be true.
Relevant: short circuit evaluation

Understanding underscore's implementation of isNaN

Taken from the underscore.js source:
_.isNaN = function(obj) {
return _.isNumber(obj) && obj != +obj;
};
Why did they do it this way? Is the above implementation equivalent to:
_.isNaN = function(obj) {
return obj !== obj;
};
If it is, why the "more complicated" version? If it is not, what are the behavioural differences?
_.isNaN(new Number(NaN)) returns true.
And that's by design.
var n = new Number(NaN);
console.log(_.isNaN(n), n!==n); // logs true, false
The host environment (e.g. web-browser environment) may introduce other values that aren't equal to themselves. The _.isNumber(obj) part makes sure that the input is a Number value, so that _.isNaN only returns true if the NaN value is passed.
If + is given before of any value with no preceding value to + , JavaScript engine will try to convert that variable to Number.If it is valid it will give you the Number else it will return NaN. For example
+ "1" // is equal to integer value 1
+ "a1" // will be NaN because "a1" is not a valid number
In above case
+"a1" != "a1" // true, so this is not a number, one case is satisfied
+"1" == "1" // true, so it is number
Another simple case would be, why the below expression give this output
console.log("Why I am " + typeof + "");
// returns "Why I am number"
Because +"" is 0.
If you want to check whether it is a number or not you could use the below function
function isNumber(a){
/* first method : */ return (+a == a);
/* second method : */ return (+(+a) >= 0);
// And so many other exists
}
Someone correct me if I am wrong somewhere..
I found one case for _.isNaN
It shows different result with the native one if you pass there an object
_.isNaN({}) => false
//but
isNaN({}) => true

Why using this method to return a function or value?

I'm just wondering why should I use this method to return a function :
clusters.prototype.get_local_storage_data = function(data_key) {
return +(this.localStorage.getItem(data_key) || 1);
};
What does the +() do there and why using that ? Is there a better way of returning the function or 1 if what the function gets is null ?
Using the + before a value forces that value to become a number. In the case above, the data key will be converted to a number (if it's found), or the number 1 will be returned. Either way, the result will be converted to a number.
+null; // 0
+"3.14"; // 3.14
+1; // 1
It's just ensuring that no matter what the output is, you will be returning a number.
The + is there to cast the result to a number -
typeof +"123" // "number"
The way it's implemented looks just fine, and doesn't need to be changed.
The + is just making sure the return value is a number or else 1 would be true and not the number one. It's a shortcut for:
Number( expression )

jQuery: why is an integer being added to a variable like a string?

So I'm trying to take the variable that increments in a for statement, and add an integer to it... but for some reason, it's adding the integer as though it were a string; other operations like subtraction or multiplication work as expected.
Why is this happening? Edit: I've added the whole function; the problem in question is where I try to add 2 to the variable x.
What confuses me is that I'm able to use x no problem, in an .eq() object for example...
$(function() {
$('textarea').bind('paste', function (e){
inputGroup = $(this).parent();
var ob = $(this);
if (e.type == 'paste'){
setTimeout(function(){
var data = ob.val();
var tabbed = data.replace(/\n/g, "\t");
var cells = tabbed.split("\t");
for(var x in cells) {
foo = x + 2;
alert(foo);
$(inputGroup).find('input').eq(x).val(cells[x]);
}
}, 1);
}
});
});
Why is this happening?
Because x is a string that just looks like a number. Cast to Number first and you'll get the result you expect:
"1" + 2 = "12"
Number("1") + 2 = 3
EDIT : Now that I see you are using split to turn a string into an array, your problem is definitely that you are concatenating strings. Cast to Number first, and your problem is solved.
Yes other arithmetic operations will work, since they will implicitly cast the operands to Numbers. Confusingly, "2" * 3 will in fact evaluate to the integer 6. Welcome to Javascript.
-tjw
Without more code, specifically the initialization of cells, I can't tell you the exact reason. But you can simply call parseInt() on x to turn it into an integer for addition
for(var x in cells) {
foo = parseInt(x, 10) + 2;
$(inputGroup).find('input').eq(foo).val(cells[x]);
}
Because + is a String concatenation but there is no equivalent String method for * or / so when using those it cast the value as a Number. Just cast x as an integer:
for(var x in cells) {
foo = parseInt(x, 10) + 2;
$(inputGroup).find('input').eq(foo).val(cells[x]);
}
The 10 in parseInt is saying to use a base 10 number system (as opposed to hex 16, e.g.).
As others have mentioned, x is a string. That's why.
There's a nice trick for casting strings as numbers in JavaScript that hasn't been mentioned though:
for(var x in cells) {
// Without the "var" here, you're setting a global
// variable during each loop iteration.
var foo = +x + 2;
$(inputGroup).find('input').eq(foo).val(cells[x]);
}

Categories

Resources