I am trying to understand the core of JavaScript. I know it doesnt have much implementation value. If you dont want to answer, just leave it. However, I will appreciate if you could help to understand the following type coercion while applying addition(+).
1.
null + null // 0
2.
null + undefined; // NaN
3.
null + NaN; // NaN
4.
1 + null; //1
5.
true + null; //1
6.
true + [null]; //"true"
I know null is an empty or missing object. I will appreciate, if you can explain steps in type coercion or unary(+) operation here. Thanks for reading the question.
This is covered in 11.6.1 The Addition operator ( + ) - feel free to read it and follow the rules.
The first five cases can be explained by looking at ToNumber:
Value ToNumber(Value)
--------- ---------------
null 0
undefined NaN
NaN NaN
1 1
true 1
And 0 + 0 == 0 (and 1 + 0 == 1), while x + NaN or NaN + x evaluates to NaN. Since every value above is also a primitive, ToPrimitive(x) evaluates to x (where x is not a string) and the "string concatenation clause" was not invoked.
The final case is different in that it results from the ToPrimitive (which ends up calling Array.prototype.toString) on the array which results in a string value. Thus it ends up applying ToString, not ToNumber, and follows as such:
true + [null]
=> true + "" // after ToPrimitive([null]) => ""
=> "true" + "" // after ToString(true) => "true"
=> "true" // via String Concatenation
Conclusions derived from analysing results
true coerces to 1 (and false to 0).
null coerces to 0.
undefined coerces to NaN.
Arrays behave as:
under unary + (+[]):
their first element if length is 1
0 if they're empty
NaN if there's more than 1 element
under binary + (1+[]):
coerces both operators to strings and joins them
All operations on NaN return NaN
Related
I know Lodash often adds some extra checks or niceties to functions that already exist in JavaScript but it's not clear what _.toNumber specifically does that I wouldn't get with parseInt.
I'd prefer to use Lodash only when it provides benefits that aren't there with existing JavaScript functions but I can't see any in this case.
I think it is much better to simply look at the _.toNumber source and that would practically answer your question:
function toNumber(value) {
if (typeof value == 'number') {
return value;
}
if (isSymbol(value)) {
return NAN;
}
if (isObject(value)) {
var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
value = isObject(other) ? (other + '') : other;
}
if (typeof value != 'string') {
return value === 0 ? value : +value;
}
value = value.replace(reTrim, '');
var isBinary = reIsBinary.test(value);
return (isBinary || reIsOctal.test(value))
? freeParseInt(value.slice(2), isBinary ? 2 : 8)
: (reIsBadHex.test(value) ? NAN : +value);
}
As you can see it does a bunch of other things in comparison to parseInt. To be more specific:
console.log(_.toNumber(1), parseInt(1)) // same
console.log(_.toNumber('1'), parseInt('1')) // same
console.log(_.toNumber('b'), parseInt('b')) // same
console.log(_.toNumber({}), parseInt({})) // same
console.log(_.toNumber(' 1 '), parseInt(' 1 ')) // same
console.log(_.toNumber([1]), parseInt([1])) // same
console.log(_.toNumber(' 1a1 '), parseInt(' 1a1 ')) // NaN 1
console.log(_.toNumber([1,2]), parseInt([1,2])) // NaN 1
console.log(_.toNumber(false), parseInt(false)) // 0 NaN
console.log(_.toNumber(!0), parseInt(!0)) // 1 NaN
console.log(_.toNumber(!!0), parseInt(!!0)) // 0 NaN
console.log(_.toNumber(5e-324), parseInt(5e-324)) // 5e-324 5
console.log(_.toNumber(5.5), parseInt(5.5)) // 5.5 5
console.log(_.toNumber(null), parseInt(null)) // 0 NaN
console.log(_.toNumber(Infinity),parseInt(Infinity)) // Infinity NaN
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
So to summarize _.isNumber gives you more expected / consistent and I would argue safer results when it comes to parsing input with arrays, decimals, falsy values and strings. It would check the entire input vs parseInt which only cares about the first valid value as you can see from the examples above. It also handles better the negate operator (!) etc.
So overall it does have its uses vs parseInt
Note: What is a gotcha here is that both _.toNumber and parseInt return NaN for undefined which considering how _.toNumber deals with the rest of the falsy values one would expect to return 0 vs NaN:
console.log(_.toNumber(undefined), parseInt(undefined)) // NaN NaN
_.toNumber converts a given input to a number if such a conversion is possible, otherwise returns NaN. The parseInt and parseFloat methods also work in same manner (the former will only return integers though), however, they are much more lax in their parsing rules. _.toNumber is significantly more restrictive.
For eg, with same input '5.2a', parseInt would return 5, parseFloat would return 5.2, and _.toNumber would return NaN. The former two ignore everything after the first unrecognised character and return the number formed by all parsed characters till that point. The last one however returns NaN if an unrecognised character is encountered.
_.toNumber is comparable and functionally same to Number function.
This question already has answers here:
In JavaScript, why is "0" equal to false, but when tested by 'if' it is not false by itself?
(15 answers)
Closed 8 years ago.
Why is the result of the following two statements different?
('0' ? 'a' : 'b') /* -> 'a' */
('0' == true ? 'a' : 'b') /* -> 'b' */
jsFiddle testcase
Edit:
I should add that I suspect the '0' first statement to be cast to boolean to be compared - which should be exactly the same as " '0' == true "
Obviously this is not true.
First, for completeness:
('0' ? 'a' : 'b')
is 'a', because '0' is a non-empty string, which always evaluates to true:
String: The result is false if the argument is the empty String (its length is zero);
otherwise the result is true.
Now to '0' == true.
Two type conversions will take place here. We can follow this in the specification, section 11.9.3, The Abstract Equality Comparison Algorithm.
The operands are denoted as x and y (x == y).
In our case, x is a string ('0') and y is a Boolean (true). Hence step 7 is executed:
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
When booleans are converted to numbers, the following conversion takes place:
Boolean: The result is 1 if the argument is true. The result is +0 if the argument is false.
Now we have
'0' == 1
which matches the condition in step 5:
If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
How strings are converted to numbers is more complex but of course can also be found in the specification.
So the final comparison is
0 == 1
which is false (step 1. a. vi.)
('0' ? 'a' : 'b'); /* -> 'a' */
0 is a string value, every non-empty string is evaluated as true, and not tested as boolean. If quotes are removed:
(0 ? 'a' : 'b'); /* -> 'b' */
you will receive b - now 0 is not a string and evaluated as false!
('0' == true ? 'a' : 'b'); /* -> 'b' */
0 is evaluated as bool Both are evaluated as numbers, which is false. Point 11.9.3 The Abstract Equality Comparison Algorithm from the specs show that a number of conversions may be executed to compare the same type of variables.
Because '0' is not equal 1, so it is not equal to true, though it is not false.
In the first case, when '0' is casted to bool, casting operator returns true for everything that is not 0.
Mostly because JavaScript is pretty darn inconsistent when it comes to truth-iness. But the answer is:
In this case, '0' is converted directly to a Boolean, and '0', being a non-empty string, is true.
In this case, no conversion takes place; a string is not equal to a boolean value.
That's because '0' is trueish (in an if statement), but not considered equal to true. Just like both 3 and 17 are trueish, but not equal.
('0' ? 'a' : 'b') --> 0 is false, '0' is some string therefore NOT FALSE
0,null or '' (empty string) is treated as FALSE in this case
('0' == true ? 'a' : 'b') --> as mentioned by others some_string compared to boolean TRUE is NOT TRUE
var PgrtiJr = {
"TWfbR": +((!+[] + !![] + !![] + !![] + []) + (!+[] + !![] + !![]))
};
PgrtiJr.TWfbR -= +((+!![] + []) + (+!![]));
console.log(parseInt(PgrtiJr.TWfbR, 10));
I have above mentioned js code. I executed this code on http://math.chapman.edu/~jipsen/js/. Can anybody explain me how it is equal to 32?
and can you recommend any python library that can evaluate this expression in python
tried execjs but no luck
You need to understand few important things about JavaScript's loose typing. Lets start with simpler things, specific to your question.
An empty array literal is considered truthy, but when you apply unary + operator, the array will be converted to a String and which will then be converted to a number. So, internally +[] evaluates to 0.
console.log(+[]);
// 0
Since [] is truthy, double negating it with logical not operator will give you true, which when used in an arithmetic expression, evaluate to 1, since 1 is loosely equal to true.
console.log(!![], 3 + !![]);
// true 4
Apart from all these, when we use an array literal with + operator, the array will be converted to a string and since one part of the expression is string, the other part of the expression will also be converted to string and string concatenation takes place. So the resulting object will be of type string.
console.log(typeof 1, typeof [], typeof (1 + []), 1 + []);
// number object string 1
With this basic understanding, lets analyze the first expression.
+((!+[]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]))
Lets first take,
(!+[]+!![]+!![]+!![]+[])
Here, +[] evaluates to 0 and logical not makes it as true. Since we use it in an expression with a numeric operand, true is treated as 1. And as per our point 2 seen above, !![] evaluates to 1. So, the expression becomes 1 + 1 + 1 + 1 + [], which is actually 4 + []. And as per point 3, the number 4 will become string 4.
The same way, other part of the expression, (!+[]+!![]+!![]) becomes, 1 + 1 + 1 and which is actually 3. So when you do '4' + 3, you will get '43', which is a string. Now, we have a unary + operator which converts this string to a number. So, the result of evaluation of this expression becomes 43, which is a number.
The other part of the expression,
PgrtiJr.TWfbR -= +((+!![]+[])+(+!![]))
will be evaluated like this
+((1 + []) + 1)
and then
+('1' + 1)
and then
+'11'
which is then evaluated to 11. Since PgrtiJr.TWfbR is actually 43, 43 - 11 becomes 32. That is why you are getting 32 as the answer.
[] is an object that is equal to null.
!![] is a "boolean" that equals to true. (twice ! of null ( = false) )
!+[] is a "boolean" that equals to true.
and if we add a [] after this expressions, they will be converted to string.
so
(!+[]+!![]+!![]+!![]+[]) will be a string that equals 4
(!+[]+!![]+!![]) will be a string that equals 3
hence (!+[]+!![]+!![]+!![]+[]) + (!+[]+!![]+!![]) will be a string that equals 43
and +(!+[]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]) will be a number that again equals 43
in the same way +((+!![]+[])+(+!![])) will equal to 11
so total of expression will equal to 43 - 11 = 32
My app behaves abnormally and figured the code below is going to else statement unexpectedly.
code
if(" " != 0) {
console.log("whitespace is not zero");
}
else {
console.log("bar");
}
Firebug output
bar
I thought whitespace is a String and comparison against integer zero should return false like the case above but I don't know why it is going to else statement.
Could anyone explain why?
In JS, " " == 0 equals true with loose/lenient comparison, you should use strict equality operator ===/!== instead:
" " !== 0
To get to first condition.
Tests:
console.log(" " == 0); // true
console.log(" " === 0); // false
Loose Comparison Chart:
"" == "0" // false
0 == "" // true
0 == "0" // true
false == "false" // false
false == "0" // true
false == undefined // false
false == null // false
null == undefined // true
" \t\r\n" == 0 // true
Strict Comparison Chart:
"" === "0" // false
0 === "" // false
0 === "0" // false
false === "false" // false
false === "0" // false
false === undefined // false
false === null // false
null === undefined // false
" \t\r\n" === 0 // false
(Examples by Douglas Crockford)
Good Practice:
Whenever possible, use strict equality operator because with loose equality operator, JS does type coercion which is a performance hit and doesn't always yield expected results as shown in above comparison charts.
The other answers have told you how to solve the issue. My answer will attempt to actually explain why you have the issue in the first place (since that was your actual question!)
The behaviour of the == operator is defined in the spec as the "abstract equality algorithm". It states (among other things) the following:
If Type(x) is String and Type(y) is Number, return the result of the
comparison ToNumber(x) == y.
One of the rules of the ToNumber operation on a string is as follows:
The MV of StringNumericLiteral ::: StrWhiteSpace is 0...
Once the exact MV for a String numeric literal has been determined, it is then rounded to a value of the Number type. If the MV is 0, then the rounded value is +0 unless the first non white space character in the String numeric literal is ‘-’, in which case the rounded value is −0.
So we are left with +0 == 0 which fits another rule of the abstract equality algorithm:
If x is the same Number value as y, return true.
This is the case because 0 is the same as +0. Even if one of the numbers was -0 it would return true:
If x is +0 and y is −0, return true.
If x is −0 and y is +0, return
true.
When you use != rather than !==, JavaScript tries to coerce the values on either side to the same type. In this case, I think it converts both to numbers.
" " happens to be 0 as a number. (Try " " * 1. It evaluates to 0.)
This also works with other operators like > or *. So " " > -1 is true and " " * 100 is 0. This also means you can do neat stuff like "6" * "7" and get 42. Unfortunately, this breaks down with + since it is inexplicably overloaded to do both math and string concatenation.
I personally like all of this behavior except for +. Others' opinions vary.
to compare with the number 0, you must use the strict comparison ===
if(" " !== 0) {
console.log("whitespace is not zero");
}
else {
console.log("bar");
}
a "truth table" found here: Which equals operator (== vs ===) should be used in JavaScript comparisons?
because a string with whitespaces is converted to 0. So
To compare:
if(" " !== 0) {
....
Code-snippet 1:
if ( !x ) { /* do stuff */ }
Code-snippet 2:
if ( x == 0 ) { /* do stuff */ }
For what values of x do these two code-snippets differ?
I am asking because, although I read the chapter on == in the spec, I still find it hard to deal with situations like the above (where it is combined with ToBoolean coercion).
btw, I want to know this just for the sake of knowing it (I want to understand the language), so don't bother telling me about === or asking me what x is.
Update: I corrected the fist snippet. I meant !x.
[] == 0 is true; ![] is false
null == 0 is false; !null is true
NaN == 0 is false; !NaN is true
undefined == 0 is false; !undefined is true
!x will check whether x is "falsy".
x == 0 will check whether x is "equivalent to" 0.
Both of these terms are defined by the Javascript spec.
The following will give you true for the first and false for the second snippet:
NaN
null
undefined
And these will give you false for the first and true for the second snippet:
[]
"0" and any other string that converts to 0 using Number(x) such as "00", "000", "+0", and "-0" (which I will now call "noughty strings")
an array containing a single element that is 0, null, undefined or an empty or noughty string.
For everything else you'll get the same result for both snippets, although there may be one or two more cases I haven't thought of.
Here's an interesting one with regard to a non-empty String that has only space characters:
!!" "; // true
" " == true; // false
This is because when you do a == comparison, and one of the values being compared is a number or a boolean, an attempt is made to convert the other value to a number.
The reason you get the different result is that a string with only space characters converts to the number 0 (or falsey), while a string with only spaces converted to boolean via !! is seen as a non-empty string, and therefore true.
So:
var x = " ";
alert( !x ); // false
alert( x == 0 ); // true
EDIT:
Probably the key thing to remember is that when comparing a number or boolean to a non number type, == uses toNumber conversion if possible, while ! uses toBoolean conversion. They're not always the same.
It is easy to see the result of the toBoolean conversion using !!. As in:
alert( !![] ); // true
But you can't really see the result of the toNumber conversion when using ==.
You can, however, use the unary + to see the result of a toNumber conversion. As in:
alert( +[] ); // 0
I'm pretty sure that what happens in the case of an Array, is that it first gets a toString call. Therefore:
// ---------------------toString result-------toNumber result (from string)
alert( +[] ); // "" 0
alert( +[""] ); // "" 0
alert( +[" "] ); // " " 0
alert( +[0] ); // "0" 0
alert( +["0"] ); // "0" 0
alert( +["3"] ); // "3" 3
alert( +[3,4] ); // "3,4" NaN
Short answer: the two are almost always the same but not 100% the same.
An example would be (!'0') which is false whereas ('0' == 0) is true
Details:
From: http://www.joeyjavas.com/2007/08/04/javascript-true-false-checking-for-boolean-values/
Checking if a value is true or false is simple in JavaScript. All values evaluate to true, except for:
0
-0
null
undefined
NaN
empty string
false
Therefore, (!x) will be true for all of the above values of x and only those.
As for (x == 0), it will be true for any value of x which - when converted according to "==" conversion rules - is converted to 0 when compared to a number (for example, Boolean false value). Other examples that compare true to ==0 are objects which generate 0 from their valueOf() methods, or a string '0', or an empty Array ([])
The first test will succeed when x is non-zero, or evaluates to an object (as opposed to null or undefined), or is a non-empty string. So if x is 0 then the condition fails, but if it is "0" then it succeeds.
The second test will succeed when x is convertible to 0. This means it must not be null, undefined, or an object to pass this test. And it may be "0" or "".
In other words, these conditionals are not opposites. The value "0" will pass both tests, for example.
Code Snippet 1 will execute if x is "falsy" value. In Javascript, this means 0, -0, null, undefined, NaN, "", or false. Code Snippet 2, however, will only execute if x is zero. Unlike the first condition, this does not include other "falsy" values.
The difference between the two is that
if ( x ) { ... }
Tests whether x is "truthy"
Whereas
if ( x == 0 ) { ... }
Does type coercion between x and 0.
I presume you mean something like
if (x == 0) vs if (!x)
The main difference is type coercion of x to a number vs checking if x is falsy.
Clearly NaN itself will never equal 0 since its not a number. undefined will also coerce to NaN so that is not caught by == 0 I can't give a good explanation why null is not caught by 0 since Number(null) == 0
After some lookups, have to change my awnser.
There's no simple logic, implicit equality operations follows an algorithm.
http://interglacial.com/javascript_spec/a-11.html#a-11.9.3
I can't sum it up better then what the algoritm describes, it would just get more confusing.
So it's (!x) is equivalent to (typeof x === false) aka (not true)
And (x == 0) gets compared by algorithm.