// original code
// (beautified)
var _calls_ = 10, a = 100, b = 10, c = 0;
function f0(Math, NaN_1, foo) {
function f1(a, bar_2) {
function f2() {
return;
}
var a_2 = f2();
function f3(Infinity_1, a_2, NaN_2) {
for (var brake4 = 5; (c = 1 + c, (Infinity_1 && (Infinity_1[c = 1 + c, (5 ^ "object") >> ("number" <= "foo") ^ (25 <= -5) >>> ("undefined" << "b")] = "number" == 25)) >> (false & [ , 0 ][1]) != (-5 << this !== -4 >>> 5)) && brake4 > 0; --brake4) {
c = 1 + c, (a_2 && (a_2[c = 1 + c, (-5 / "a" ^ -4 % 2) !== (25 / 3 || 23..toString() << 5)] = 25 >= {})) >= true + NaN > "bar" * "" * ([ , 0 ].length === 2 !== 2);
}
}
var a_2 = f3(b = a, "number");
function f4(Infinity) {
return c = 1 + c, 1 / -0 <= ([] == 24..toString()) > 25 % 4 / (2 <= {});
if (c = 1 + c, c = c + 1, (c = c + 1, 0) | "foo" ^ "object") {
c = 1 + c, -5 + "bar" == (23..toString() || this) & ([ , 0 ][1] === this) << (([ , 0 ].length === 2) <= "undefined");
}
}
var NaN_1 = f4(--b + NaN_1);
}
var foo_2 = f1([]);
}
var a = f0(-2, typeof parseInt_1);
console.log(null, a, b, c, Infinity, NaN, undefined);
// uglified code
// (beautified)
var l = 0;
(function(o) {
for (var i = 5; l = 1 + l, (o && (o[l = 1 + l, 5] = !1)) >> 0 != (-5 << this != -4 >>> 5) && 0 < i; --i) {
l = 1 + (1 + l);
}
})([]), console.log(null, void 0, -1, l = 1 + l, 1 / 0, NaN, void 0);
md5-3533a76cd2c5302f437ada69de95ec9a
original result:
null undefined NaN 23 Infinity NaN undefined
uglified result:
null undefined -1 23 Infinity NaN undefined
md5-05bb5c6d3430d9d00bc646a04c7cdb81
minify(options):
{
"compress": {
"passes": 1000000,
"unsafe": true
},
"toplevel": true
}
Suspicious compress options:
evaluate
passes
reduce_vars
unsafe
unused
Suspicious options:
toplevel
```
Today I learned that unary increment/decrement of arrays yield valid scalar numbers in some cases:
$ echo 'a = [3], a++, console.log(a);' | node
4
$ echo 'a = [3], --a, console.log(a);' | node
2
$ echo 'a = [], --a, console.log(a);' | node
-1
$ echo 'a = [null], a++, console.log(a);' | node
1
$ echo 'a = [undefined], a++, console.log(a);' | node
1
$ echo 'a = [3, 4], --a, console.log(a);' | node
NaN
because unary decrement and increment is syntax sugar for a = Number(a) - 1 and a = Number(a) + 1 respectively, which in turn relies on the odd valid conversion from array to number if the array is of length 0 or 1:
$ echo 'console.log(+[3], +[], +[null], +[undefined], +[3,4])' | node
3 0 0 0 NaN
I tried following the rabbit hole in the ES5.1 spec but my head exploded:
Much easier to just run the code on various browsers & platforms than reading the specifications, if not because the former don't necessarily follow the latter.
Reading the spec can give you the rationale for the strange behavior - what motivated the designers to adopt that approach in the first place. That is what I was trying to determine, but failed. The effect appears to be the culmination of a bunch of individually reasonable defaults and conversions that lead to a ridiculous result in the aggregate.
Just for completeness sake, here's AST_Hole 馃懟
$ echo 'console.log(+[,])' | node
0
But not two of them...
$ echo 'console.log(+[,,])' | node
NaN
The specification also has the problem of having to codify the legacy behavior of the original JS interpreter implementation which can't be changed for reasons of backwards compatibility. It's not likely that this particular behavior was intended as it's not terribly useful - probably just an oversight at the time.