(![]+[])[+[]]... Explain why this works - javascript

alert((![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]);
The output of this code is: fail. Why?

As #Mauricio commented (![]+[])[+[]] is "f" (the first char of "false"), (![]+[])[+!+[]]) is "a", etc...
How does it work?
Let's examine the first character, 'f':
(![]+[])[+[]]; // 'f'
The first part of the expression—between parentheses—is composed by ![]+[], the first operand of the Addition operator is ![] and it will produce false, because an array object—as any other Object instance—is truthy, and applying the Logical (!) NOT unary operator, it produces the value false, for example.
![]; // false, it was truthy
!{}; // false, it was truthy
!0; // true, it was falsey
!NaN; // true, it was falsey
After it, we have the second operand of the addition, an empty Array, [], this is made just to convert the false value to String, because the string representation of an empty array is just an empty string, is equivalent to:
false+[]; // "false"
false+''; // "false"
The last part, the pair of square brackets after the parentheses, they are the property accessor, and they receive an expression, which is formed by the Unary Plus Operator applied to an empty array again.
What the Unary Plus Operator does is type conversion, to Number, for example:
typeof +"20"; // "number"
One more time, this is applied to an empty Array, and as I said before, the String representation of an Array is an empty string, and when you convert an empty string to Number, it is converted to zero:
+[]; // 0, because
+[].toString(); // 0, because
+""; // 0
Therefore we can "decode" the expression to in some steps:
(![]+[])[+[]];
(false+[])[+[]];
(false+'')[+[]];
(false+'')[0];
('false')[0]; // "f"
Note that accessing characters by using the bracket notation on String values was not part of the ECMAScript 3rd. Edition Specification, (that's why the charAt method existed).
However this kind of "index properties" that represent the characters of a string were standardized on ECMAScript 5, and even before the standardization the feature was available in a good number of browsers (even in IE8 (standards mode)).

Related

I'm wondering Why this expression is equal to "fail"? [duplicate]

alert((![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]);
The output of this code is: fail. Why?
As #Mauricio commented (![]+[])[+[]] is "f" (the first char of "false"), (![]+[])[+!+[]]) is "a", etc...
How does it work?
Let's examine the first character, 'f':
(![]+[])[+[]]; // 'f'
The first part of the expression—between parentheses—is composed by ![]+[], the first operand of the Addition operator is ![] and it will produce false, because an array object—as any other Object instance—is truthy, and applying the Logical (!) NOT unary operator, it produces the value false, for example.
![]; // false, it was truthy
!{}; // false, it was truthy
!0; // true, it was falsey
!NaN; // true, it was falsey
After it, we have the second operand of the addition, an empty Array, [], this is made just to convert the false value to String, because the string representation of an empty array is just an empty string, is equivalent to:
false+[]; // "false"
false+''; // "false"
The last part, the pair of square brackets after the parentheses, they are the property accessor, and they receive an expression, which is formed by the Unary Plus Operator applied to an empty array again.
What the Unary Plus Operator does is type conversion, to Number, for example:
typeof +"20"; // "number"
One more time, this is applied to an empty Array, and as I said before, the String representation of an Array is an empty string, and when you convert an empty string to Number, it is converted to zero:
+[]; // 0, because
+[].toString(); // 0, because
+""; // 0
Therefore we can "decode" the expression to in some steps:
(![]+[])[+[]];
(false+[])[+[]];
(false+'')[+[]];
(false+'')[0];
('false')[0]; // "f"
Note that accessing characters by using the bracket notation on String values was not part of the ECMAScript 3rd. Edition Specification, (that's why the charAt method existed).
However this kind of "index properties" that represent the characters of a string were standardized on ECMAScript 5, and even before the standardization the feature was available in a good number of browsers (even in IE8 (standards mode)).

Why does Javascript isNaN function declare string negative hex values to be NaN?

Given the following example:
isNaN("-0x123"); // returns true , meaning is not a number <- Why?
isNaN(-0x123); // returns false, meaning is a number
isNaN("0x123"); // returns false, meaning is a number
parseInt("-0x123"); // returns -291
My question: why does isNaN declares negative hex strings as NaN when other similar inputs yield more reasonable outputs?
Thanks
The function isNaN() tells you whether or not a value may be coerced to a number, it says nothing about whether there exists a function that will convert the value to a number.
You will see the same behaviour if you attempt to coerce the strings to numbers:
> +"-0x123"
NaN
> +(-0x123)
-291
> +"0x123"
291
The first case you have a string that does not match Javascript's rules for a number as that doesn't allow for a leading - on a hex literal, the second case you have an expression that evaluates to a number (so 0x123 negated), the third case you have a string that does match the grammar for a number.
See http://www.ecma-international.org/ecma-262/5.1/#sec-9.3 for the exact description, but in short a string numeric literal may be an unsigned decimal literal, + or - followed by an unsigned decimal literal, or it may be a hex integer literal (and in all these cases leading and trailing whitespace is ignored). There is no option for a sign on a hex literal.
What you are expecting is this :
isNaN(parseInt("-0x123")); // returns -291
Because "-0x123" is treated as a string and not as a number. So
isNaN("-0x123");
will return false since there is no number. The MDN says:
The isNaN() function determines whether a value is NaN or not. Note:
coercion inside the isNaN function has interesting rules; you may
alternatively want to use Number.
.........
Confusing special-case behavior
Since the very earliest versions of the isNaN function specification,
its behavior for non-numeric arguments has been confusing. When the
argument to the isNaN function is not of type Number, the value is
first coerced to a Number. The resulting value is then tested to
determine whether it is NaN. Thus for non-numbers that when coerced to
numeric type result in a valid non-NaN numeric value (notably the
empty string and boolean primitives, which when coerced give numeric
values zero or one), the "false" returned value may be unexpected; the
empty string, for example, is surely "not a number." The confusion
stems from the fact that the term, "not a number", has a specific
meaning for numbers represented as IEEE-754 floating-point values. The
function should be interpreted as answering the question, "is this
value, when coerced to a numeric value, an IEEE-754 'Not A Number'
value?"

Why and how does ([![]]+[][[]])[+!+[]+[+[]]] evaluate to the letter "i"? [duplicate]

This question already has answers here:
Why does ++[[]][+[]]+[+[]] return the string "10"?
(10 answers)
(![]+[])[+[]]... Explain why this works
(1 answer)
Closed 9 years ago.
While reading this article posted on dzone I found a snippet of JavaScript originally posted on Twitter by Marcus Lagergren.
The following code apparently prints the string "fail"
(![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]];
This involves implicit type casting and I'm trying to understand how exactly this line is interpreted.
I've isolated each character
(![]+[])[+[]] prints "f"
(![]+[])[+!+[]] prints "a"
([![]]+[][[]])[+!+[]+[+[]]] prints "i"
(![]+[])[!+[]+!+[]] prints "l"
I've also managed to break down the expressions returning each letter apart from "i"
letter "f"
![] an empty array is an Object, which according to ECMAScript documentation, point 9.2 evaluates to true when converted to a boolean so this is false
false+[] as per Point 11.6.1 both arguments of the binary + operator get converted to String, therefore we get "false"+"", which evaluates "false"
+[] a unary plus operator causes a ToNumber conversion followed by a ToPrimitive conversion if the argument is an Object. The result of such conversion is determined by calling the [[DefaultValue]] internal method of the object. In case of an empty array, it defaults to 0.
(ECMAScript Documentation, sections: 11.4.6, 9.3, 9.1 )
"false"[0] we're accessing the character at index 0, hence the "f"
letter "a"
Same story, the only difference here are additional conversions in the part in square brackets (which evaluates to a number to point at another character in the string "false"), triggered by the use of unary + and ! operators.
+[] evaluates to 0, as explained above.
!0 evaluates to true as defined in Section 9.2 and Section 11.4.9. First, 0 is converted to a boolean false and then the operator inverts the value.
+true again, the unary plus triggers a ToNumber conversion, which returns a 1 for binary true
(Section 11.4.6 and 9.3)
"false"[1] returns the second character in the string, which is "a"
letter "l"
!+[] evaluates to true as explained above
true+true using the binary + on primitives triggers a ToNumber conversion. In case of true, its result is 1 and 1+1 equals 2
"false"[2] - self explanatory
letter "i"
What leaves me stumped is the letter "i". I can see that the second part (in square brackets) evaluates to the string "10" and that the first part (in parentheses) returns "falseundefined" but I can't make heads or tails of how this is happening. Could someone explain it step by step? Especially the magic that happens with square brackets? (arrays and array access)
If possible, I'd like each step to contain a link to the underlying ECMAScript rules.
What I find the most cryptic is this part: [][[]]
Your cryptic part isn't all that cryptic if you rewrite it a little:
[]['']
[] will be coerced into a string because it isn't an integer, so you're looking for a property of [] with the name '' (an empty string). You'll just get undefined, as there is no property with that name.
As for the actual letter, break the expression up into the two main components:
The string ([![]]+[][[]]):
[![]] is [false].
[][[]] is undefined.
Add them together and you get "falseundefined".
And the index: [+!+[]+[+[]]]. Some whitespace and parentheses will make the operations much clearer: [+(!(+[])) + [+[]]]:
[+[]] is [0].
+[] coerces [] to an integer, so you get 0.
!+[] coerces 0 to a boolean and negates it, so you get true.
+!+[] coerces true to an integer, so you get 1.
Add them together, and you get ["10"].
When using a string to access the properties of the array and the string happens to be an element of the array, the string is coerced into an integer and you get back the actual element of the array:
> [1, 2, 3]["0"]
1
> [1, 2, 3]["1"]
2
So your final result is:
> "falseundefined"["10"]
"i"
Read this answer for an explanation of the [false] + undefined part.
([![]]+[][[]])[+!+[]+[+[]]] has two parts :
([![]]+[][[]]) and the other which you found yourself.
![] returns false. Then we use [...] to get the .toString() behavior of +.
([]+[] is the same as [].toString()+[].toString())
the [][[]] is undefined because we're trying to access the index [] (or [].toString(), which is '') of [] which is undefined.
Sorry for the previous answered, I misread your comment totally.

How does the following piece of expression evaluates to "10" [duplicate]

This question already has answers here:
Why does ++[[]][+[]]+[+[]] return the string "10"?
(10 answers)
Closed 6 years ago.
I have recently seen an expression from a source, which looks something like below -
++[[]][+[]]+[+[]]
Entering this into the Chrome (Windows 7, Version 27.0.1453.94 m) console shows a result of "10".
Can someone explain what's happening here?
JSFiddle.
JavaScript is fairly flexible about converting between data types. The first thing to notice is that +[] evaluates to 0.* That lets us rewrite the expression as:
++[[]][0] + [0]
The next thing to notice is that ++[[]][0] is the preincrement operator applied to the first element of [[]]. Normally you can't apply ++ to an array, but JavaScript kindly converts the first element to 0, so the result is that ++[[]][0] evaluates to 1 (the first element of [[]] having now been incremented). It is kind of like this:
var a = [[]];
var b = ++a[0];
// now a will be [1] and b will be 1
That leaves us with:
1 + [0]
JavaScript now converts the int and the array to strings (since [0] is not a numeric value) and concatenates them together. Done!
* My understanding of how +[] becomes 0 is that it is a two-step process: first, [] is converted to a string primitive, which is the empty string. The empty string then converts to a number, which is zero. Via the same route, [1] evaluates to '1' and then to 1, [2] evaluates to 2, etc. However, [1, 2] evaluates to '1,2' which evaluates to NaN. (The last because the decimal point separator is ., not ,. I don't know what would happen if my locale were different.)
This expression stringifies valid Javascript constructs that yelds NaN, numbers, boolean undefined etc.
e.g.
+[] -> 0 //The unary plus operator is applied to the result of toString applied to an empty array (which is an empty string)
!+[] -> true
You can have a look also at this question,
and at the no alnum cheat sheets.
+[] is a number conversion from array to number which is 0.
and +[0] is also 0.
So the final result can be deduced to (++0) + [0] which is 1+[0].
And for a number adding an array. They are converted to string so the result is actually '10'.
You can log typeof(++[[]][+[]]+[+[]]) to verify.

Obfuscated javascript code with binary values?

This code outputs D. The question is HOW?
alert([][(![]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]]()[([][(![]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]]()+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(![]+[])[+!+[]]](+[]+[+[]])[+!+[]]);
I understand that ![] is evaluated to false or 0 and so on, but how does it execute? And how can I convert this to something humans can understand and not only Jon Skeet?
Can someone break some piece of this code and explain me what's happening?
Well, evaluating the expression in parts, at the end it is equivalent to:
[]['sort']['call']()["btoa"]("00")[1]; // "D"
Which can be simplified to :
btoa("00")[1]; // "D"
How you can "decode it"?
Simply examine the operators used, for example, we can see at first that an array literal is used, then several bracket notation property accesses are done, and a couple of invocations.
How does it work?
The trick is to chain multiple type conversions, for example, to get the f letter:
(![]+[])[+[]]
If we examine the first part, in parentheses, ![]+[], we see a boolean negation, which will return false because an array object is always truthy, and then a concatenation.
That produces the string "false", then, the second part, we see a brackets applied to that string, to access a character, and the expression +[], which results in 0.
+[] gives zero because the Array's toString method returns an empty string, for an empty array like that one, and an empty string produces to zero when it is converted to number (the unary + operator in this example).
There are just tricks like that, things that produce a string, such "true", "false", "null", "undefined", etc... and more tricks to get the numerically.
For example to get a number -to access a character-, they use again cryptic type conversion:
+[]; // 0, equivalent to +""
+!+[]; // 1, equivalent to +true
!+[]+!+[]; // 2, equivalent to +true+true
!+[]+!+[]+!+[]; // 3, equivalent to +true+true+true
It does some tricks with the javascript type conversions. As CMS pointed out, it's equivalent to: []['sort']['call']()["btoa"]("00")[1];
They build the strings by pulling them out of things like false, etc.
For example, to get the s in "sort":
Get a "false": (![]+[]) -- ![] returns false and +[] converts it to a string.
Get the value 3 with: !+[]+!+[]+!+[] - each !+[] returns true, but when you add booleans you get an integer representation. e.g. true + true = 2
Get the s with string index access notation ("false"[3] = 's'): (![]+[]) [!+[]+!+[]+!+[]]
And now you have an s. They keep doing that until they have enough to access whichever method or property they want.
![] is false. ![] + [] evaluates to 'false'. +[] is 0 so !+[] is true, etc. javascript is very strange with its implied type conversions

Categories

Resources